﻿/******************************************************************************************************
Copyright (C) 2020 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals date2ISOString, draw, mainWindow, nmr, qsTr, settings, Application, Dir, Document, File, FileDialog, MnUi, NMRProcessing, NMRSpectrum, MessageBox, Page, Peak, ProcessingParametersReporter, ProcessingParametersReporter_Configuration, SnrPeakCalculator, SpectrumQuality_Viewer, Str, Template, TextStream */

/*jslint plusplus: true, indent: 4, continue:true, bitwise: true */


/******************************ENGINE CLASS********************************
**************************************************************************/
function SpectrumQuality_Engine(aParameters) {
	'use strict';

	var result, file, stream, dataJSON, items, generalSettings, data,
		viewerInstance, generateParametersFromSettings, generalOptionsSettings;

	//General engine options
	this.validConditions = [];
	this.validConditions.push(SpectrumQuality_Engine.userCondition.EQ);
	this.validConditions.push(SpectrumQuality_Engine.userCondition.NE);
	this.validConditions.push(SpectrumQuality_Engine.userCondition.LT);
	this.validConditions.push(SpectrumQuality_Engine.userCondition.GT);
	this.validConditions.push(SpectrumQuality_Engine.userCondition.LE);
	this.validConditions.push(SpectrumQuality_Engine.userCondition.GE);
	this.limitPeakInHz = 55;
	this.doubletJValue = 1.5;
	this.debugMode = true;
	this.defaultDecimalsPrecision = 4;
	this.sizeWindowLocalBaselineCorrection = 4;
	this.clearPeaksBeforStartingEachProcess = true;
	this.snrPeakLogLevel = 2; //0: INFO; 1: ERROR; 2: INFO & ERROR
	this.deletePreviousPeaksAtSNR = true;
	this.badParametersPath = false;
	this.performSQAUsingSpectrumCopyInHiddenDocument = false;
	this.handleBlankSpaceAsNumericValueInConditionForAcquisitionParametersTest = {};
	this.handleBlankSpaceAsNumericValueInConditionForAcquisitionParametersTest.enabled = true;
	this.handleBlankSpaceAsNumericValueInConditionForAcquisitionParametersTest.regex = /\s/g;
	this.handleBlankSpaceAsNumericValueInConditionForAcquisitionParametersTest.token = "{blankSpace}";
	this.handleBlankSpaceAsNumericValueInConditionForAcquisitionParametersTest.useTokenIfOneOfConditionTermsIsBlankSpace = true;
	this.handleBlankSpaceAsNumericValueInConditionForProcessingParametersTest = {};
	this.handleBlankSpaceAsNumericValueInConditionForProcessingParametersTest.enabled = true;
	this.handleBlankSpaceAsNumericValueInConditionForProcessingParametersTest.regex = /\s/g;
	this.handleBlankSpaceAsNumericValueInConditionForProcessingParametersTest.token = "{blankSpace}";
	this.handleBlankSpaceAsNumericValueInConditionForProcessingParametersTest.useTokenIfOneOfConditionTermsIsBlankSpace = true;

	//Instance Attributes
	generateParametersFromSettings = false;
	if (aParameters !== undefined && (typeof (aParameters) === "object")) {
		this.performSQAUsingSpectrumCopyInHiddenDocument = aParameters.keepCurrentData;
		this.clearPeaksBeforStartingEachProcess = !aParameters.useCurrentAnalysis;
		this.deletePreviousPeaksAtSNR = !aParameters.useCurrentAnalysis;
		this.acquisitionParameters = aParameters.acquisitionParameters;
		this.processingParameters = aParameters.processingParameters;
		this.signalToNoiseFilterStatus = aParameters.signalToNoiseFilterStatus;
		this.signalFullSpectrum = aParameters.signalFullSpectrum;
		this.signalFrom = aParameters.signalFrom;
		this.signalTo = aParameters.signalTo;
		this.noiseAutomatic = aParameters.noiseAutomatic;
		this.noiseFrom = aParameters.noiseFrom;
		this.noiseTo = aParameters.noiseTo;
		this.snrMinValue = aParameters.snrMinValue;
		this.phaseErrorFilterStatus = aParameters.phaseErrorFilterStatus;
		this.phaseErrorCondition = aParameters.phaseErrorCondition;
		this.phaseErrorValue = aParameters.phaseErrorValue;
		this.peakFilterStatus = aParameters.peakFilterStatus;
		this.peakWidthParameters = aParameters.peakWidthParameters;
		this.peakWidthDecimals = aParameters.peakWidthDecimals;
		this.peakWidthFullSpectrum = aParameters.peakWidthFullSpectrum;
		this.peakIntensityFilterStatus = aParameters.peakIntensityFilterStatus;
		this.peakIntensityParameters = aParameters.peakIntensityParameters;
		this.peakIntensityDecimals = aParameters.peakIntensityDecimals;
		this.peakIntensityFullSpectrum = aParameters.peakIntensityFullSpectrum;
		this.purityFilterStatus = aParameters.purityFilterStatus;
		this.purityCondition = aParameters.purityCondition;
		this.purityValue = aParameters.purityValue;
		this.digitalResolutionFilterStatus = aParameters.digitalResolutionFilterStatus;
		this.digitalResolutionCondition = aParameters.digitalResolutionCondition;
		this.digitalResolutionValue = aParameters.digitalResolutionValue;

	//Parameters come from a settings file
	} else if (aParameters !== undefined && (typeof (aParameters) === "string")) {
		file = new File(aParameters);
		if (!(file.exists)) {
			this.badParametersPath = true;

		} else {
			//Get data from file
			file.open(File.ReadOnly);
			stream = new TextStream(file);
			stream.codec = "UTF-8";
			dataJSON = stream.readAll();
			generalSettings = JSON.parse(dataJSON);
			stream.flush();
			file.close();

			//Activate flag for loading parameters from settings and create the viewer instanceof
			//Get instance attributes of the viewer class and create the settings object
			viewerInstance = new SpectrumQuality_Viewer(false);
			generateParametersFromSettings = true;
		}

	//Get values from registry
	} else if (aParameters === undefined) {

		//Get instance attributes of the viewer class and create the settings object
		viewerInstance = new SpectrumQuality_Viewer(false);
		generalSettings = {};

		//Acquisition parameters
		data = settings.value(viewerInstance.acquisitionParametersGUIKey, "");
		if (data !== "") {
			generalSettings.acquisitionParameters = data;
		}

		//Processing parameters
		data = settings.value(viewerInstance.processingParametersGUIKey, "");
		if (data !== "") {
			generalSettings.processingParameters = data;
		}

		//Signal-to-Noise parameters
		data = settings.value(viewerInstance.signalToNoiseStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.signalToNoiseFilterStatus = data;
		}
		data = settings.value(viewerInstance.signalFullSpectrumKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.signalFullSpectrum = data;
		}
		data = settings.value(viewerInstance.signalFromKey, "");
		if (data !== "") {
			generalSettings.signalFrom = data;
		}
		data = settings.value(viewerInstance.signalToKey, "");
		if (data !== "") {
			generalSettings.signalTo = data;
		}
		data = settings.value(viewerInstance.noiseAutomaticKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.noiseAutomatic = data;
		}
		data = settings.value(viewerInstance.noiseFromKey, "");
		if (data !== "") {
			generalSettings.noiseFrom = data;
		}
		data = settings.value(viewerInstance.noiseToKey, "");
		if (data !== "") {
			generalSettings.noiseTo = data;
		}
		data = settings.value(viewerInstance.snrMinValueKey, "");
		if (data !== "") {
			generalSettings.snrMinValue = data;
		}

		//Phase parameters
		data = settings.value(viewerInstance.phaseStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.phaseFilterStatus = data;
		}
		data = settings.value(viewerInstance.phaseConditionKey, "-");
		if (data !== "-") {
			generalSettings.phaseCondition = data;
		} else {
			generalSettings.phaseCondition = SpectrumQuality_Engine.phaseErrorCondition;
		}
		data = settings.value(viewerInstance.phaseValueKey, "");
		if (data !== "") {
			generalSettings.phaseValue = data;
		}

		//Peak width control
		data = settings.value(viewerInstance.peakStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.peakFilterStatus = data;
		}
		data = settings.value(viewerInstance.peakWidthGUIKey, "");
		if (data !== "") {
			generalSettings.peakWidth = data;
		}

		//Intensity control
		data = settings.value(viewerInstance.peakIntensityStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.peakIntensityFilterStatus = data;
		}
		data = settings.value(viewerInstance.peakIntensityGUIKey, "");
		if (data !== "") {
			generalSettings.peakIntensity = data;
		}

		//Purity control
		data = settings.value(viewerInstance.purityStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.purityFilterStatus = data;
		}
		data = settings.value(viewerInstance.purityConditionKey, "-");
		if (data !== "-") {
			generalSettings.purityCondition = data;
		} else {
			generalSettings.purityCondition = SpectrumQuality_Engine.purityCondition;
		}
		data = settings.value(viewerInstance.purityValueKey, "");
		if (data !== "") {
			generalSettings.purityValue = data;
		}

		//Digital Resolution control
		data = settings.value(viewerInstance.digitalResolutionStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			generalSettings.digitalResolutionFilterStatus = data;
		}
		data = settings.value(viewerInstance.digitalResolutionConditionKey, "-");
		if (data !== "-") {
			generalSettings.digitalResolutionCondition = data;
		} else {
			generalSettings.digitalResolutionCondition = SpectrumQuality_Engine.digitalResolutionCondition;
		}
		data = settings.value(viewerInstance.digitalResolutionValueKey, "");
		if (data !== "") {
			generalSettings.digitalResolutionValue = data;
		}

		//Get settings related to the general options
		generalOptionsSettings = SpectrumQuality_Viewer.getGeneralOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityGeneralSettings.ui');

		//Load parameters from settings
		generateParametersFromSettings = true;

	} else {
		result = {};
		result.status = SpectrumQuality_Engine.status.UNTESTED;
		result.logDetail += "[ERROR]: Incorrect parameters format";
	}

	if (generateParametersFromSettings) {

		//Get general options settings
		if (generalOptionsSettings !== undefined) {
			if (generalOptionsSettings.widgets !== undefined) {
				this.performSQAUsingSpectrumCopyInHiddenDocument = generalOptionsSettings.keepCurrentData;
				this.clearPeaksBeforStartingEachProcess = !generalOptionsSettings.useCurrentAnalysis;
				this.deletePreviousPeaksAtSNR = !generalOptionsSettings.useCurrentAnalysis;
			}
		}

		//Set data to the GUI components
		if (generalSettings !== undefined && generalSettings.acquisitionParameters !== undefined && typeof (generalSettings.acquisitionParameters) === "string") {
			items = JSON.parse(generalSettings.acquisitionParameters);
			this.acquisitionParameters = SpectrumQuality_Viewer.getDataFromTableWidget(items, viewerInstance.acquisitionParameter.checkBoxParameter, viewerInstance.acquisitionParameter.parameterParameter, viewerInstance.acquisitionParameter.conditionParameter, viewerInstance.acquisitionParameter.valueParameter);
		} else {
			this.acquisitionParameters = undefined;
		}
		if (generalSettings !== undefined && generalSettings.processingParameters !== undefined && typeof (generalSettings.processingParameters) === "string") {
			items = JSON.parse(generalSettings.processingParameters);
			this.processingParameters = SpectrumQuality_Viewer.getDataFromTableWidget(items, viewerInstance.processingParameter.checkBoxParameter, viewerInstance.processingParameter.parameterParameter, viewerInstance.processingParameter.conditionParameter, viewerInstance.processingParameter.valueParameter);
		} else {
			this.processingParameters = undefined;
		}
		this.signalToNoiseFilterStatus = generalSettings.signalToNoiseFilterStatus;
		this.signalFullSpectrum = generalSettings.signalFullSpectrum;
		this.signalFrom = generalSettings.signalFrom;
		this.signalTo = generalSettings.signalTo;
		this.noiseAutomatic = generalSettings.noiseAutomatic;
		this.noiseFrom = generalSettings.noiseFrom;
		this.noiseTo = generalSettings.noiseTo;
		this.snrMinValue = generalSettings.snrMinValue;
		this.phaseErrorFilterStatus = generalSettings.phaseFilterStatus;
		this.phaseErrorCondition = generalSettings.phaseCondition;
		this.phaseErrorValue = generalSettings.phaseValue;
		this.peakFilterStatus = generalSettings.peakFilterStatus;
		if (generalSettings !== undefined && generalSettings.peakWidth !== undefined && typeof (generalSettings.peakWidth) === "string") {
			items = JSON.parse(generalSettings.peakWidth);
			this.peakWidthParameters = SpectrumQuality_Viewer.getDataFromTableWidget(items, viewerInstance.peakWidth.checkBoxParameter, viewerInstance.peakWidth, viewerInstance.peakWidth.conditionParameter, viewerInstance.peakWidth.valueParameter);
		} else {
			this.peakWidthParameters = undefined;
		}
		if (generalSettings !== undefined && generalSettings.peakIntensity !== undefined && typeof (generalSettings.peakIntensity) === "string") {
			items = JSON.parse(generalSettings.peakIntensity);
			this.peakIntensityParameters = SpectrumQuality_Viewer.getDataFromTableWidget(items, viewerInstance.peakIntensity.checkBoxParameter, viewerInstance.peakIntensity, viewerInstance.peakIntensity.conditionParameter, viewerInstance.peakIntensity.valueParameter);
		} else {
			this.peakIntensityParameters = undefined;
		}
		this.purityFilterStatus = generalSettings.purityFilterStatus;
		this.purityCondition = generalSettings.purityCondition;
		this.purityValue = generalSettings.purityValue;
		this.digitalResolutionFilterStatus = generalSettings.digitalResolutionFilterStatus;
		this.digitalResolutionCondition = generalSettings.digitalResolutionCondition;
		this.digitalResolutionValue = generalSettings.digitalResolutionValue;
	}

	//We set this parameters to default values because the first one in not stored in the settings and the second one is not used any longer
	if (this.peakWidthDecimals === undefined) {
		this.peakWidthDecimals = this.defaultDecimalsPrecision;
	}

	if (this.peakWidthFullSpectrum === undefined) {
		this.peakWidthFullSpectrum = false;
	}

	if (this.peakIntensityDecimals === undefined) {
		this.peakIntensityDecimals = this.defaultDecimalsPrecision;
	}

	if (this.peakIntensityFullSpectrum === undefined) {
		this.peakIntensityFullSpectrum = false;
	}

	//------------------------------INSTANCE METHODS-------------------------------------
	SpectrumQuality_Engine.prototype.getCurrentDate = function () {

		return date2ISOString(new Date());
	};

	SpectrumQuality_Engine.prototype.cloneSpectrumInHiddenDocument = function (aSpectrum) {

		var spectrum, doc, auxPage, page;

		if (aSpectrum !== undefined) {
			if (aSpectrum.uuid !== undefined && aSpectrum.uuid !== "") {
				if (aSpectrum.isValid()) {
					spectrum = aSpectrum;
					doc = new Document();
					auxPage = doc.newPage();
					page = new Page(auxPage);
					if (page !== undefined) {
						if (page.uuid !== undefined && page.uuid !== "") {
							page.cloneItems(spectrum);
						}
					}
				}
			}
		}

		return doc;
	};

	SpectrumQuality_Engine.prototype.existsParameter = function (aParameter, aSpectrum, aType) {

		var i, result, parameters;

		if (aType === "processing parameter") {
			try {
				result = aSpectrum.proc.getParameter(aParameter.parameter);
			} catch (Err) {
				result = undefined;
			}
		} else if (aType === "acquisition parameter") {
			parameters = aSpectrum.paramNames();
			for (i = 0; i < parameters.length; i++) {
				if (parameters[i] === aParameter.parameter) {
					result = aSpectrum.getParam(aParameter.parameter);
					break;
				}
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.existsCondition = function (aCondition) {

		var i, result;

		result = false;
		for (i = 0; i < this.validConditions.length; i++) {
			if (aCondition === this.validConditions[i]) {
				result = true;
				break;
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.snrParametersValidation = function () {

		var aux, result, logDetail;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		logDetail = "";

		if (!this.signalFullSpectrum && isNaN(this.signalFrom)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The signal from range ppm parameter (" + this.signalFrom + ") is not a valid number";
		} else {
			this.signalFrom = Number(this.signalFrom);
		}

		if (!this.signalFullSpectrum && isNaN(this.signalTo)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The signal to range ppm parameter (" + this.signalTo + ") is not a valid number";
		} else {
			this.signalTo = Number(this.signalTo);
		}

		if (!this.noiseAutomatic && isNaN(this.noiseFrom)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The noise from range ppm parameter (" + this.noiseFrom + ") is not a valid number";
		} else {
			this.noiseFrom = Number(this.noiseFrom);
		}

		if (!this.noiseAutomatic && isNaN(this.noiseTo)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The noise to range ppm parameter (" + this.noiseTo + ") is not a valid number";
		} else {
			this.noiseTo = Number(this.noiseTo);
		}

		if (result.status === SpectrumQuality_Engine.status.PASSED) {
			if (this.signalFullSpectrum && this.signalFrom > this.signalTo) {
				aux = this.signalFrom;
				this.signalFrom = this.signalTo;
				this.signalTo = aux;
			}
			if (this.noiseFrom > this.noiseTo) {
				aux = this.noiseFrom;
				this.noiseFrom = this.noiseTo;
				this.noiseTo = aux;
			}
			if (this.snrMinValue === undefined || this.snrMinValue.toString().trim() === "") {
				this.snrMinValue = undefined;
			}
		} else {
			result.log = "\n\t[ERROR]: The SNR filter has not been used because of the following reasons:";
			result.log += logDetail;
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.phaseErrorParametersValidation = function () {

		var result, logDetail;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		logDetail = "";

		if (this.phaseErrorCondition !== undefined && this.phaseErrorCondition.toString() !== "" && !this.existsCondition(this.phaseErrorCondition)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The phase error condition (" + this.phaseErrorCondition + ") is not a valid condition: available conditions are: " + this.validConditions;
		}

		if (this.phaseErrorValue === undefined || this.phaseErrorValue.toString().trim() === "") {
			this.phaseErrorValue = undefined;
		} else {
			if (isNaN(this.phaseErrorValue)) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				logDetail += "\n\t\t[ERROR]: The phase error value (" + this.phaseErrorValue + ") is not a valid number";
			} else {
				this.phaseErrorValue = Number(this.phaseErrorValue);
			}
		}

		if (result.status === SpectrumQuality_Engine.status.UNTESTED) {
			result.log = "\n\t[WARNING]: The phase error filter will be performed but will not be evaluated due to the following reasons:";
			result.log += logDetail;
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.peakWidthFilterParametersValidation = function () {

		var aux, result, logDetail, prop, types;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		logDetail = "";

		aux = Peak.Types;
		if (this.peakType !== "Any" && aux[this.peakType] === undefined) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			types = "";
			for (prop in aux) {
				if (aux.hasOwnProperty(prop)) {
					types += prop + ", ";
				}
			}
			types = types.replace(/\,\s$/, "");
			logDetail += "\n\t\t[ERROR]: The peak type value parameter (" + this.peakType + ") is not valid: available types are: " + types;
		}
		if (isNaN(this.peakHeightAt)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak height at parameter (" + this.peakHeightAt + ") is not a valid number";
		} else {
			this.peakHeightAt = Number(this.peakHeightAt);
		}

		if (isNaN(this.peakValue)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak value parameter (" + this.peakValue + ") is not a valid number";
		} else if (this.peakValue !== "") {
			this.peakValue = Number(this.peakValue);
		}

		if (this.peakCondition !== undefined && this.peakCondition.toString() !== "" && !this.existsCondition(this.peakCondition)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak condition value parameter (" + this.peakCondition + ") is not a valid condition: available conditions are: " + this.validConditions;
		}

		if (!this.peakWidthFullSpectrum && isNaN(this.peakFrom)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak from range ppm parameter (" + this.peakFrom + ") is not a valid number";
		} else {
			this.peakFrom = Number(this.peakFrom);
		}

		if (!this.peakWidthFullSpectrum && isNaN(this.peakTo)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak to range ppm parameter (" + this.peakTo + ") is not a valid number";
		} else {
			this.peakTo = Number(this.peakTo);
		}

		if (this.peakAsymmetryCondition !== undefined && this.peakAsymmetryCondition.toString() !== "" && !this.existsCondition(this.peakAsymmetryCondition)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak asymmetry condition value parameter (" + this.peakAsymmetryCondition + ") is not a valid condition: available conditions are: " + this.validConditions;
		}

		if (this.peakAsymmetryValue !== undefined && isNaN(this.peakAsymmetryValue)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak asymmetry value parameter (" + this.peakAsymmetryValue + ") is not a valid number";
		} else if (this.peakAsymmetryValue !== "" && this.peakAsymmetryValue !== undefined) {
			this.peakAsymmetryValue = Number(this.peakAsymmetryValue);
		}

		if (result.status === SpectrumQuality_Engine.status.PASSED) {
			if (this.peakWidthDecimals === undefined || isNaN(this.peakWidthDecimals)) {
				this.peakWidthDecimals = this.defaultDecimalsPrecision;
			}

			if (!this.peakWidthFullSpectrum && this.peakFrom > this.peakTo) {
				aux = this.peakTo;
				this.peakTo = this.peakFrom;
				this.peakFrom = aux;
			}

			if (this.peakValue === undefined || this.peakValue.toString().trim() === "") {
				this.peakValue = undefined;
			}

			if (this.peakAsymmetryValue === undefined || this.peakAsymmetryValue.toString().trim() === "") {
				this.peakAsymmetryValue = undefined;
			}

		} else {
			result.log = "\n\t[ERROR]: The peak width filter has not be used because of the following reasons:";
			result.log += logDetail;
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.peakIntensityFilterParametersValidation = function () {

		var aux, result, logDetail, prop, types;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		logDetail = "";

		aux = Peak.Types;
		if (this.peakType !== "Any" && aux[this.peakType] === undefined) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			types = "";
			for (prop in aux) {
				if (aux.hasOwnProperty(prop)) {
					types += prop + ", ";
				}
			}
			types = types.replace(/\,\s$/, "");
			logDetail += "\n\t\t[ERROR]: The peak intensity type value parameter (" + this.peakType + ") is not valid: available types are: " + types;
		}

		if (isNaN(this.peakIntensityValue)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak intensity value parameter (" + this.peakIntensityValue + ") is not a valid number";
		} else if (this.peakIntensityValue !== "") {
			this.peakIntensityValue = Number(this.peakIntensityValue);
		}

		if (this.peakIntensityCondition !== undefined && this.peakIntensityCondition.toString() !== "" && !this.existsCondition(this.peakIntensityCondition)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak intensity condition value parameter (" + this.peakIntensityCondition + ") is not a valid condition: available conditions are: " + this.validConditions;
		}

		if (!this.peakIntensityFullSpectrum && isNaN(this.peakIntensityFrom)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak intensity from range ppm parameter (" + this.peakIntensityFrom + ") is not a valid number";
		} else {
			this.peakIntensityFrom = Number(this.peakIntensityFrom);
		}

		if (!this.peakIntensityFullSpectrum && isNaN(this.peakIntensityTo)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The peak intensity to range ppm parameter (" + this.peakIntensityTo + ") is not a valid number";
		} else {
			this.peakIntensityTo = Number(this.peakIntensityTo);
		}

		if (result.status === SpectrumQuality_Engine.status.PASSED) {
			if (this.peakIntensityDecimals === undefined || isNaN(this.peakIntensityDecimals)) {
				this.peakIntensityDecimals = this.defaultDecimalsPrecision;
			}

			if (!this.peakIntensityFullSpectrum && this.peakIntensityFrom > this.peakIntensityTo) {
				aux = this.peakIntensityTo;
				this.peakIntensityTo = this.peakIntensityFrom;
				this.peakIntensityFrom = aux;
			}

			if (this.peakIntensityValue === undefined || this.peakIntensityValue.toString().trim() === "") {
				this.peakIntensityValue = undefined;
			}

		} else {
			result.log = "\n\t[ERROR]: The peak intensity filter has not be used because of the following reasons:";
			result.log += logDetail;
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.purityParametersValidation = function () {

		var result, logDetail;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		logDetail = "";

		if (this.purityCondition !== undefined && this.purityCondition.toString() !== "" && !this.existsCondition(this.purityCondition)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The purity condition (" + this.purityCondition + ") is not a valid condition: available conditions are: " + this.validConditions;
		}

		if (this.purityValue === undefined || this.purityValue.toString().trim() === "") {
			this.purityValue = undefined;
		} else {
			if (isNaN(this.purityValue)) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				logDetail += "\n\t\t[ERROR]: The purity value (" + this.purityValue + ") is not a valid number";
			} else {
				this.purityValue = Number(this.purityValue);
			}
		}

		if (result.status === SpectrumQuality_Engine.status.UNTESTED) {
			result.log = "\n\t[WARNING]: The purity filter will be performed but will not be evaluated due to the following reasons:";
			result.log += logDetail;
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.digitalResolutionParametersValidation = function () {

		var result, logDetail;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		logDetail = "";

		if (this.digitalResolutionCondition !== undefined && this.digitalResolutionCondition.toString() !== "" && !this.existsCondition(this.digitalResolutionCondition)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			logDetail += "\n\t\t[ERROR]: The digital resolution condition (" + this.digitalResolutionCondition + ") is not a valid condition: available conditions are: " + this.validConditions;
		}

		if (this.digitalResolutionValue === undefined || this.digitalResolutionValue.toString().trim() === "") {
			this.digitalResolutionValue = undefined;
		} else {
			if (!this.digitalResolutionValue || isNaN(this.digitalResolutionValue)) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				logDetail += "\n\t\t[ERROR]: The digital resolution value (" + this.digitalResolutionValue + ") is not a valid number";
			} else {
				this.digitalResolutionValue = Number(this.digitalResolutionValue);
			}
		}

		if (result.status === SpectrumQuality_Engine.status.UNTESTED) {
			result.log = "\n\t[WARNING]: The digital resolution filter will be performed but will not be evaluated due to the following reasons:";
			result.log += logDetail;
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.checkIsInsideTheLimits = function (aFromPPM, aToPPM, aMinPPMSpectrum, aMaxPPMSpectrum) {

		var result;

		result = (aMinPPMSpectrum <= aFromPPM && aMaxPPMSpectrum >= aToPPM);

		return result;

	};

	SpectrumQuality_Engine.prototype.evaluateCondition = function (aValue1, aCondition, aValue2, aHandleBlankSpaceAsNumericValue) {

		var condition, conditionStatement, result, value1, value2,
			flagNumberValue1, flagNumberValue2, evalValue1, evalValue2,
			auxValueEval1, auxValueEval2, auxValueEval3, flagNumericCondition,
			flagEvaluateCondition, equalRegExp, notEqualRegExp, greaterEqualRegExp,
			lowerEqualRegExp;

		//Initialize vars
		result = {};
		value1 = aValue1;
		value2 = aValue2;
		flagNumberValue1 = false;
		flagNumberValue2 = false;

		//Build regular expression for replacement
		equalRegExp = new RegExp(SpectrumQuality_Engine.userCondition.EQ, "g");
		notEqualRegExp = new RegExp(SpectrumQuality_Engine.userCondition.NE, "g");
		greaterEqualRegExp = new RegExp(SpectrumQuality_Engine.userCondition.GE, "g");
		lowerEqualRegExp = new RegExp(SpectrumQuality_Engine.userCondition.LE, "g");

		//Prepare data for condition
		condition = aCondition.toString();
		condition = condition.replace(equalRegExp, SpectrumQuality_Engine.programmingCondition.EQ);
		condition = condition.replace(notEqualRegExp, SpectrumQuality_Engine.programmingCondition.NE);
		condition = condition.replace(greaterEqualRegExp, SpectrumQuality_Engine.programmingCondition.GE);
		condition = condition.replace(lowerEqualRegExp, SpectrumQuality_Engine.programmingCondition.LE);

		//Check if values are numbers. That fixes the problem if they are equals but one is number and other not
		//In this case both will be handled as numbers even though they were string data types
		//We do not consider empty string as 0 number
		if (aValue1 !== undefined) {
			if (typeof (aValue1) === "string") {
				if (aValue1.toString().trim() !== "") {
					if (!isNaN(aValue1)) {
						flagNumberValue1 = true;
					}
				}
			} else if (!isNaN(aValue1)) {
				flagNumberValue1 = true;
			}
		}
		if (aValue2 !== undefined) {
			if (typeof (aValue2) === "string") {
				if (aValue2.toString().trim() !== "") {
					if (!isNaN(aValue2)) {
						flagNumberValue2 = true;
					}
				}
			} else if (!isNaN(aValue2)) {
				flagNumberValue2 = true;
			}
		}

		//Using multi-line string that contains line break tokens or quotes in eval statement may throw a parse error exception because is quite tricky
		//To fix the problem, we have to properly escape the values being passed into eval such that they are literal strings which you appear to use them as inside the eval statement
		//We must escape backslash in new line tokens and the same type of quotes used to build the string sent to the eval function
		//Since the eval argument is a string, to compare data types in eval an explicit conversion must be made when constructing the variable
		if (aValue1 !== undefined) {
			if ((typeof (aValue1) === "number") || flagNumberValue1) {
				auxValueEval1 = Number(aValue1);
				evalValue1 = "Number(" + auxValueEval1 + ")";
				value1 = auxValueEval1;
			} else if ((typeof (aValue1) === "string") && (aValue1 !== "")) {
				auxValueEval1 = aValue1.replace(/'/g, "\\'");
				auxValueEval2 = auxValueEval1.replace(/\r/g, "\\r");
				auxValueEval3 = auxValueEval2.replace(/\n/g, "\\n");
				evalValue1 = "'" + auxValueEval3 + "'";
			} else {
				evalValue1 = "'" + aValue1 + "'";
			}
		}

		if (aValue2 !== undefined) {
			if ((typeof (aValue2) === "number") || flagNumberValue2) {
				auxValueEval1 = Number(aValue2);
				evalValue2 = "Number(" + auxValueEval1 + ")";
				value2 = auxValueEval1;
			} else if ((typeof (aValue2) === "string") && (aValue2 !== "")) {
				auxValueEval1 = aValue2.replace(/'/g, "\\'");
				auxValueEval2 = auxValueEval1.replace(/\r/g, "\\r");
				auxValueEval3 = auxValueEval2.replace(/\n/g, "\\n");
				evalValue2 = "'" + auxValueEval3 + "'";
			} else {
				evalValue2 = "'" + aValue2 + "'";
			}
		}

		//Values will always be handled as strings
		if (aHandleBlankSpaceAsNumericValue !== undefined && aHandleBlankSpaceAsNumericValue.enabled) {

			//Initialize vars
			result.status = false;
			flagEvaluateCondition = false;

			//Determining the condition type
			if (flagNumberValue1 && flagNumberValue2) {
				flagNumericCondition = true;
			} else {
				flagNumericCondition = false;
			}

			//This condition only makes sense with numeric values (avoid strings)
			if (condition === SpectrumQuality_Engine.programmingCondition.GT || condition === SpectrumQuality_Engine.programmingCondition.GE || condition === SpectrumQuality_Engine.programmingCondition.LE || condition === SpectrumQuality_Engine.programmingCondition.LT) {
				if (flagNumericCondition) {
					flagEvaluateCondition = true;
				}

			//This condition makes sense for any data type
			} else if (condition === SpectrumQuality_Engine.programmingCondition.EQ || condition === SpectrumQuality_Engine.programmingCondition.NE) {
				flagEvaluateCondition = true;
			}

			//At this point it makes sense the condition be evaluated
			if (flagEvaluateCondition) {
				//Compare conditions
				conditionStatement = evalValue1 + condition + evalValue2;
				/*jslint evil:true */
				result.status = eval(conditionStatement);
			}

			//If compare not visible results we have to perform some special actions
			//Get readable values by replacing blank spaces for a "visible" token
			if (aHandleBlankSpaceAsNumericValue.useTokenIfOneOfConditionTermsIsBlankSpace !== undefined && aHandleBlankSpaceAsNumericValue.useTokenIfOneOfConditionTermsIsBlankSpace) {
				if (typeof (aValue1) === "string" || flagNumberValue1) {
					if (typeof (aValue2) === "string" || flagNumberValue2) {
						if (aValue1.toString().trim() === "") {
							value1 = aValue1.toString().replace(aHandleBlankSpaceAsNumericValue.regex, aHandleBlankSpaceAsNumericValue.token);
						}
						if (aValue2.toString().trim() === "") {
							value2 = aValue2.toString().replace(aHandleBlankSpaceAsNumericValue.regex, aHandleBlankSpaceAsNumericValue.token);
						}
					}
				}
			//Two terms of the condition must contain "nothing" to use the blankSpace token
			} else {
				if (typeof (aValue1) === "string") {
					if (typeof (aValue2) === "string") {
						if (aValue1.trim() === "") {
							if (aValue2.trim() === "") {
								value1 = aValue1.replace(aHandleBlankSpaceAsNumericValue.regex, aHandleBlankSpaceAsNumericValue.token);
								value2 = aValue2.replace(aHandleBlankSpaceAsNumericValue.regex, aHandleBlankSpaceAsNumericValue.token);
							}
						}
					}
				}
			}

		//Possible numeric values will be managed here
		} else {

			//Compare conditions
			conditionStatement = evalValue1 + condition + evalValue2;
			/*jslint evil:true */
			result.status = eval(conditionStatement);
		}

		//Determine the final status of the test
		if (!result.status) {
			result.status = SpectrumQuality_Engine.status.FAILED;
		} else {
			result.status = SpectrumQuality_Engine.status.PASSED;
		}

		//Display the performed condition
		condition = condition.replace(/\=\=\=/g, "=");
		condition = condition.replace(/!==/g, "≠");
		condition = condition.replace(/>=/g, "≥");
		condition = condition.replace(/<=/g, "≤");
		result.condition = value1 + condition + value2;

		return result;
	};

	SpectrumQuality_Engine.prototype.processParameter = function (aParameter, aSpectrum, aType, aHandleBlankSpaceAsNumericValue) {

		var result, parameterValue, condition, value, resultCondition;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";

		//Check if the parameter exists
		parameterValue = this.existsParameter(aParameter, aSpectrum, aType);
		if (parameterValue !== undefined) {

			//Prepare data for condition and evaluate condition
			condition = aParameter.condition.toString();
			value = aParameter.value;
			resultCondition = this.evaluateCondition(parameterValue, condition, value, aHandleBlankSpaceAsNumericValue);
			result.status = resultCondition.status;
			if (result.status === SpectrumQuality_Engine.status.FAILED) {
				result.log = "\n\t[WARNING]: The " + aParameter.parameter + " " + aType + " does not meet the condition: " + resultCondition.condition;
			} else if (this.debugMode !== undefined && this.debugMode) {
				result.log = "\n\t[INFO]: The " + aParameter.parameter + " " + aType + " meets the condition: " + resultCondition.condition;
			}

		} else {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log = "\n\t[WARNING]: The following " + aType + ": " + aParameter.parameter + " does not exist into the " + aType + " table";
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.processParameters = function (aObject, aSpectrum, aType, aHandleBlankSpaceAsNumericValue) {

		var result, auxResult, properties, parameter, flagTested;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";
		result.used = false;
		flagTested = false;

		for (properties in aObject) {
			if (aObject.hasOwnProperty(properties)) {
				if (!isNaN(properties)) {
					for (parameter in aObject[properties]) {
						if (aObject[properties].hasOwnProperty(parameter)) {
							if (parameter === "checked" && aObject[properties][parameter]) {
								result.used = true;
								if (aObject[properties][parameter]) {
									if (aType) {
										auxResult = this.processParameter(aObject[properties], aSpectrum, "acquisition parameter", aHandleBlankSpaceAsNumericValue);
									} else {
										auxResult = this.processParameter(aObject[properties], aSpectrum, "processing parameter", aHandleBlankSpaceAsNumericValue);
									}
									switch (auxResult.status) {
									case SpectrumQuality_Engine.status.FAILED:
										flagTested = true;
										result.status = SpectrumQuality_Engine.status.FAILED;
										result.log += auxResult.log;
										break;
									case SpectrumQuality_Engine.status.PASSED:
										flagTested = true;
										if (this.debugMode !== undefined && this.debugMode) {
											result.log += auxResult.log;
										}
										if (result.status === SpectrumQuality_Engine.status.UNTESTED) {
											result.status = SpectrumQuality_Engine.status.PASSED;
										}
										break;
									case SpectrumQuality_Engine.status.UNTESTED:
										result.log += auxResult.log;
										if (!flagTested) {
											result.status = SpectrumQuality_Engine.status.UNTESTED;
										}
										break;
									}
								}
							}
						}
					}
				}
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.calculateMedian = function (aArray) {

		var median, half, totalElements;

		aArray.sort(function (a, b) { return a.width - b.width; });
		totalElements = aArray.length;
		half = Math.floor(totalElements / 2);

		if (totalElements % 2) {
			median = aArray[half];
		} else {
			median = aArray[half];
			if (aArray[half - 1].width < aArray[half].width) {
				median = aArray[half - 1];
			}
		}

		return median;
	};

	SpectrumQuality_Engine.prototype.findPeak = function (aPeakList, aPeakType, aFullSpectrum, aFromPPM, aToPPM) {

		var i, candidatePeaks, result, peak, peakTypes, delta, fullSpectrum;

		candidatePeaks = [];
		peakTypes = Peak.Types;
		fullSpectrum = aFullSpectrum || (aFromPPM === undefined || aToPPM === undefined || isNaN(aFromPPM) || isNaN(aToPPM));

		//Look for peaks 
		for (i = 0; i < aPeakList.count; i++) {

			//Get current peak
			peak = aPeakList.at(i);
			delta = peak.delta();

			//Check if the peak meets the constraints
			if (fullSpectrum || (delta >= aFromPPM && delta <= aToPPM)) {
				if (aPeakType === "Any" || peak.type === peakTypes[aPeakType]) {
					candidatePeaks.push({});
					candidatePeaks[candidatePeaks.length - 1].width = peak.width();
					candidatePeaks[candidatePeaks.length - 1].intensity = peak.intensity;
					candidatePeaks[candidatePeaks.length - 1].delta = delta;
					candidatePeaks[candidatePeaks.length - 1].id = peak.id;
				}
			}
		}

		//We have to get only a peak
		if (candidatePeaks.length >= 3) {
			result = this.calculateMedian(candidatePeaks);
		} else if (candidatePeaks.length === 2) {
			result = candidatePeaks[0];
			if (candidatePeaks[1].width < candidatePeaks[0].width) {
				result = candidatePeaks[1];
			}
		} else if (candidatePeaks.length === 1) {
			result = candidatePeaks[0];
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.findIsolatedPeak = function (aMultipletList, aPeakList, aPeakType, aFullSpectrum, aFromPPM, aToPPM) {

		var i, j, k, result, multiplet, peak, peakArray, peakTypes, delta, fullSpectrum,
			candidatePeaks, CS_ReferencePeak, flagExistPeak, jlist, jlistValue;

		candidatePeaks = [];
		CS_ReferencePeak = undefined;
		peakTypes = Peak.Types;
		fullSpectrum = aFullSpectrum || (aFromPPM === undefined || aToPPM === undefined || isNaN(aFromPPM) || isNaN(aToPPM));

		//We must include the CS_reference because Mnova will not include a CS_Reference peak into a multiplet
		if (aPeakType === "Any" || aPeakType === "CS_Ref") {

			//Iterate throw all peaks in order to look for the highest CS_Reference peak type
			for (i = 0; i < aPeakList.count; i++) {

				//Get current peak
				peak = aPeakList.at(i);
				delta = peak.delta();

				//Check for the range and peak type
				if (peak.type === peakTypes.CS_Ref) {
					if (fullSpectrum || (delta >= aFromPPM && delta <= aToPPM)) {
						if (aPeakType === "Any" || peak.type === peakTypes[aPeakType]) {
							if (CS_ReferencePeak === undefined) {
								CS_ReferencePeak = peak;
							} else if (peak.intensity > CS_ReferencePeak.intensity) {
								CS_ReferencePeak = peak;
							}
						}
					}
				}
			}

			//Add the CS_Reference peak to the the array to take it into account
			if (CS_ReferencePeak !== undefined) {
				candidatePeaks.push({});
				candidatePeaks[candidatePeaks.length - 1].width = CS_ReferencePeak.width();
				candidatePeaks[candidatePeaks.length - 1].intensity = CS_ReferencePeak.intensity;
				candidatePeaks[candidatePeaks.length - 1].delta = CS_ReferencePeak.delta();
				candidatePeaks[candidatePeaks.length - 1].id = CS_ReferencePeak.id;
			}
		}

		//Firstly, we get all peaks with the same type
		for (i = 0; i < aMultipletList.count; i++) {
			multiplet = aMultipletList.at(i);
			peakArray = [];
			peakArray = multiplet.peaks;
			//Only peaks which belongs a singlets will be taking into account
			if (multiplet.category === "s") {
				for (j = 0; j < peakArray.length; j++) {
					peak = aPeakList.byId(peakArray[j]);
					//Exclude the labile ones
					if (!(peak.flags & Peak.Flags.Labile)) {
						//Check intervals for each isolated peak
						delta = peak.delta();
						if (fullSpectrum || (delta >= aFromPPM && delta <= aToPPM)) {
							if (aPeakType === "Any" || peak.type === peakTypes[aPeakType]) {
								flagExistPeak = false;
								//Although a peak can't belong to more than one singlet, just in case we ensure we do not add a repeated peak
								for (k = 0; k < candidatePeaks.length && !flagExistPeak; k++) {
									if (candidatePeaks[k].id === peak.id) {
										flagExistPeak = true;
									}
								}
								if (!flagExistPeak) {
									candidatePeaks.push({});
									candidatePeaks[candidatePeaks.length - 1].width = peak.width();
									candidatePeaks[candidatePeaks.length - 1].intensity = peak.intensity;
									candidatePeaks[candidatePeaks.length - 1].delta = delta;
									candidatePeaks[candidatePeaks.length - 1].id = peak.id;
								}
							}
						}
					}
				}
			}
		}

		/*For the 'most convenient' one possibility would be to use the median, but only if there are more than 3 peaks.
		If there is only 2 peaks, I would use this:
		i) If one of them has been classified as labile, discard it and use the other
		ii) If none were selected as labile, use the narrowest one */
		if (candidatePeaks.length >= 3) {
			result = this.calculateMedian(candidatePeaks);
		} else if (candidatePeaks.length === 2) {
			result = candidatePeaks[0];
			if (candidatePeaks[1].width < candidatePeaks[0].width) {
				result = candidatePeaks[1];
			}
		} else if (candidatePeaks.length === 1) {
			result = candidatePeaks[0];
		} else {
			//This approach looks for the doublets because there is not at least a singlet.
			candidatePeaks = [];
			for (i = 0; i < aMultipletList.count; i++) {
				multiplet = aMultipletList.at(i);
				if (multiplet.category === "d") {
					jlist = multiplet.jList(false);
					if (jlist.count === 1) {
						peakArray = [];
						peakArray = multiplet.peaks;
						jlistValue = jlist.at(0);
						if (jlistValue <= this.doubletJValue) {
							for (j = 0; j < peakArray.length; j++) {
								peak = aPeakList.byId(peakArray[j]);
								//Exclude the labile ones
								if (!(peak.flags & Peak.Flags.Labile)) {
									//Check intervals for each isolated peak
									delta = peak.delta();
									if (fullSpectrum || (delta >= aFromPPM && delta <= aToPPM)) {
										if (aPeakType === "Any" || peak.type === peakTypes[aPeakType]) {
											flagExistPeak = false;
											for (k = 0; k < candidatePeaks.length && !flagExistPeak; k++) {
												if (candidatePeaks[k].id === peak.id) {
													flagExistPeak = true;
												}
											}
											if (!flagExistPeak) {
												candidatePeaks.push({});
												candidatePeaks[candidatePeaks.length - 1].width = peak.width();
												candidatePeaks[candidatePeaks.length - 1].intensity = peak.intensity;
												candidatePeaks[candidatePeaks.length - 1].delta = delta;
												candidatePeaks[candidatePeaks.length - 1].id = peak.id;
											}
										}
									}
								}
							}
						}
					}
				}
			}
			if (candidatePeaks.length >= 3) {
				result = this.calculateMedian(candidatePeaks);
			} else if (candidatePeaks.length === 2) {
				result = candidatePeaks[0];
				if (candidatePeaks[1].width < candidatePeaks[0].width) {
					result = candidatePeaks[1];
				}
			} else if (candidatePeaks.length === 1) {
				result = candidatePeaks[0];
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.getMaximumSNRValue = function (aSpectrum) {

		var i, peakList, result, currentPeak, auxCurrentValue, currentValue;

		result = {};
		peakList = aSpectrum.peaks();
		result.noPeaks = true;
		for (i = 0; i < peakList.count; i++) {
			currentPeak = peakList.at(i);
			currentValue = currentPeak.annotation;
			auxCurrentValue = currentValue.split(":");
			if (auxCurrentValue.length > 1) {
				currentValue = Number(auxCurrentValue[1].toString().trim());
				if (i === 0) {
					result.noPeaks = false;
					result.maxValue = currentValue;
					result.ppm = currentPeak.delta();
				} else if (currentValue > result.maxValue) {
					result.maxValue = currentValue;
					result.ppm = currentPeak.delta();
				}
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.processSNR = function (aSpectrum, aSignalFullSpectrum, aSignalFromPPM, aSignalToPPM, aNoiseAutomatic, aNoiseFromPPM, aNoiseToPPM, aMinValue, aDocument) {

		var result, parameters, zoom, snrPeakCalculatorInstance, horizontalUnits, verticalUnits, ppmFrom, ppmTo, originalLimits, snrMaxValue, spectrumLimits, snrIssue;

		result = {};
		parameters = {};
		originalLimits = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		zoom = aSpectrum.getScaleLimits();
		result.log = "";

		//Delete previous peaks
		if (this.clearPeaksBeforStartingEachProcess !== undefined && this.clearPeaksBeforStartingEachProcess) {
			aSpectrum.peaks().clear();
		}

		//Set parameters to engine by using an object sent pattern
		parameters.noiseStartX = aNoiseFromPPM;
		parameters.noiseEndX = aNoiseToPPM;
		parameters.signalStartX = aSignalFromPPM;
		parameters.signalEndX = aSignalToPPM;
		parameters.apply = 0; //0: 1D, 1: 2D, 2: 1D and 2D
		parameters.logLevel = this.snrPeakLogLevel;
		parameters.spectrum = aSpectrum;
		parameters.deleteOldPeaks = this.deletePreviousPeaksAtSNR;
		parameters.noiseAutomatic = false;

		if (aSignalFullSpectrum || aNoiseAutomatic) {

			//We ensure we always work in ppm units
			spectrumLimits = aSpectrum.getFullScaleLimits();
			verticalUnits = aSpectrum.getProperty("axes.vertical.units").toString().toLowerCase();
			horizontalUnits = aSpectrum.getProperty("axes.horizontal.units").toString().toLowerCase();
			ppmFrom = aSpectrum.unitsToUnits(horizontalUnits, "ppm", spectrumLimits.fromX, aSpectrum.dimCount);
			ppmTo = aSpectrum.unitsToUnits(horizontalUnits, "ppm", spectrumLimits.toX, aSpectrum.dimCount);
			originalLimits.fromX = Number(ppmFrom);
			originalLimits.toX = Number(ppmTo);
			if (aSpectrum.dimCount === 2 && verticalUnits !== "unknown") {
				ppmFrom = aSpectrum.unitsToUnits(verticalUnits, "ppm", spectrumLimits.fromY, 1);
				ppmTo = aSpectrum.unitsToUnits(verticalUnits, "ppm", spectrumLimits.toY, 1);
				originalLimits.fromY = Number(ppmFrom);
				originalLimits.toY = Number(ppmTo);
			}
			spectrumLimits = originalLimits;
		}

		if (aSignalFullSpectrum) {
			parameters.signalStartX = Number(spectrumLimits.fromX);
			parameters.signalEndX = Number(spectrumLimits.toX);
		}

		//The SnrPeakCalculator provides the automatic noise feature
		if (aNoiseAutomatic) {
			parameters.noiseStartX = undefined;
			parameters.noiseEndX = undefined;
			parameters.automaticNoise = true;
		}

		//Call to the SNR calculator engine
		snrPeakCalculatorInstance = new SnrPeakCalculator(parameters);
		if (snrPeakCalculatorInstance.status) {
			snrPeakCalculatorInstance.process();
			if (!snrPeakCalculatorInstance.status) {
				snrIssue = snrPeakCalculatorInstance.logDetail.replace(/\[INFO\]:|\[ERROR\]:|\[WARNING\]:/g, "\t\t[SnrPeakCalculator]: ").replace(/\n$/g, "");
				result.log += "\n\t[ERROR]: The SNR filter has not been used because the SNR Calculator engine has reported a problem: \n" + snrIssue;
				result.status = SpectrumQuality_Engine.status.UNTESTED;
			} else {
				snrMaxValue = this.getMaximumSNRValue(aSpectrum);
				if (snrMaxValue.noPeaks) {
					result.status = SpectrumQuality_Engine.status.UNTESTED;
					result.log += "\n\t[WARNING]: It has not been possible to obtain an SNR value because there is not a peak within the signal region";
				} else if (snrMaxValue.maxValue === undefined) {
					result.status = SpectrumQuality_Engine.status.UNTESTED;
					result.log += "\n\t[WARNING]: It has not been possible to obtain an SNR value";
				} else if (isNaN(snrMaxValue.maxValue)) {
					result.status = SpectrumQuality_Engine.status.UNTESTED;
					result.log += "\n\t[ERROR]: The SNR value obtained is not a number";
				} else {
					result.log += "\n\t[INFO]: Peak at: " + snrMaxValue.ppm.toFixed(this.defaultDecimalsPrecision) + " ppm";
					if (aNoiseAutomatic === undefined || aNoiseAutomatic) {
						result.log += "\n\t[INFO]: Automatic noise region has used: " + snrPeakCalculatorInstance.automaticNoiseResults.to.toFixed(this.defaultDecimalsPrecision) + " to " + snrPeakCalculatorInstance.automaticNoiseResults.from.toFixed(this.defaultDecimalsPrecision) + " ppm";
					} else {
						result.log += "\n\t[INFO]: Noise region: " + parameters.noiseStartX.toFixed(this.defaultDecimalsPrecision) + " to " + parameters.noiseEndX.toFixed(this.defaultDecimalsPrecision) + " ppm";
					}
					snrMaxValue = Number(snrMaxValue.maxValue);
					result.log += "\n\t[INFO]: SNR value: " + snrMaxValue;
					if (this.snrMinValue !== undefined) {
						if (snrMaxValue > aMinValue) {
							if (this.debugMode !== undefined && this.debugMode) {
								result.log += "\n\t[INFO]: SNR value: " + snrMaxValue + " > SNR threshold value assigned by the user: " + aMinValue;
							}
						} else if (snrMaxValue === aMinValue) {
							if (this.debugMode !== undefined && this.debugMode) {
								result.log += "\n\t[INFO]: SNR value: " + snrMaxValue + " = SNR threshold value assigned by the user: " + aMinValue;
							}
						} else {
							result.log += "\n\t[WARNING]: SNR value: " + snrMaxValue + " < SNR threshold value assigned by the user: " + aMinValue;
							result.status = SpectrumQuality_Engine.status.FAILED;
						}
					}
				}
			}
		} else {
			snrIssue = snrPeakCalculatorInstance.logDetail.replace(/\[INFO\]:|\[ERROR\]:|\[WARNING\]:/g, "\t\t[SnrPeakCalculator]: ").replace(/\n$/g, "");
			result.log += "\n\t[ERROR]: The SNR Calculator engine has reported a problem: " + snrIssue;
			result.status = SpectrumQuality_Engine.status.UNTESTED;
		}

		aSpectrum.zoom(zoom);
		aSpectrum.update();
		aDocument.update();

		return result;
	};

	SpectrumQuality_Engine.prototype.processPhaseError = function (aSpectrum, aPhaseErrorCondition, aPhaseErrorValue) {


		var result, resultCondition, orPh0, orPh1, proposedPhase, pPh0, pPh1, phaseError, auxPhaseError;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";

		if (aSpectrum.isValid()) {
			mainWindow.setBusy(qsTr("Estimating phases"));
			orPh0 = aSpectrum.proc.getParameter("PC[1].Ph0") * 180.0 / Math.PI;
			orPh1 = aSpectrum.proc.getParameter("PC[1].Ph1") * 180.0 / Math.PI;
			proposedPhase = aSpectrum.proposePhase1D();
			if (proposedPhase.ok === true) {
				pPh0 = proposedPhase.ph0 * 180.0 / Math.PI;
				pPh1 = proposedPhase.ph1 * 180.0 / Math.PI;
				phaseError = Math.abs(orPh0 - pPh0) + Math.abs(orPh1 - pPh1);
			} else {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log = "\n\t[ERROR]: Unable to determine the phase error because the proposed phase is not valid";
			}
			mainWindow.endBusy();
		} else {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log = "\n\t[ERROR]: Unable to determine the phase error because the spectrum is not valid";
		}

		//At this point we perform the test
		if (result.status === SpectrumQuality_Engine.status.PASSED) {
			if (isNaN(phaseError)) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log += "\n\t[ERROR]: Unable to determine the phase error because the returned value is not a valid number";
			} else {
				auxPhaseError = Number(phaseError).toFixed(this.defaultDecimalsPrecision);
				result.log += "\n\t[INFO]: The phase error is: " + auxPhaseError + "º";
				if (aPhaseErrorCondition !== undefined && aPhaseErrorCondition !== "" && aPhaseErrorValue !== undefined && !isNaN(aPhaseErrorValue)) {
					resultCondition = this.evaluateCondition(auxPhaseError, aPhaseErrorCondition, aPhaseErrorValue);
					result.status = resultCondition.status;
					if (result.status === SpectrumQuality_Engine.status.FAILED) {
						result.log = "\n\t[WARNING]: The phase error test does not meet the condition: " + resultCondition.condition;
					} else if (this.debugMode !== undefined && this.debugMode) {
						result.log = "\n\t[INFO]: The phase error test meets the condition: " + resultCondition.condition;
					}
				}
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.getNumberOfPeakWidthTests = function (aObject, aPropertyValue) {

		var properties, parameter, totalPeakWidthTests;

		totalPeakWidthTests = 0;
		for (properties in aObject) {
			if (aObject.hasOwnProperty(properties)) {
				if (!isNaN(properties)) {
					for (parameter in aObject[properties]) {
						if (aObject[properties].hasOwnProperty(parameter)) {
							if (parameter === aPropertyValue && aObject[properties][parameter]) {
								totalPeakWidthTests++;
							}
						}
					}
				}
			}
		}

		return totalPeakWidthTests;
	};

	SpectrumQuality_Engine.prototype.getNumberOfIntensityTests = function (aObject, aPropertyValue) {

		var properties, parameter, totalIntensityTests;

		totalIntensityTests = 0;
		for (properties in aObject) {
			if (aObject.hasOwnProperty(properties)) {
				if (!isNaN(properties)) {
					for (parameter in aObject[properties]) {
						if (aObject[properties].hasOwnProperty(parameter)) {
							if (parameter === aPropertyValue && aObject[properties][parameter]) {
								totalIntensityTests++;
							}
						}
					}
				}
			}
		}

		return totalIntensityTests;
	};

	SpectrumQuality_Engine.prototype.getPointsLocalBaselineCorrection = function (aSpectrum, aRightBoundary, aLeftBoundary) {

		var i, result, counter, averageHeightLeftSide, averageHeightRightSide, windowSize;

		result = {};
		averageHeightLeftSide = 0;
		averageHeightRightSide = 0;
		windowSize = this.sizeWindowLocalBaselineCorrection / 2;

		//The middle of the window is the left boundary. The window size is 5 points
		counter = 0;
		for (i = aLeftBoundary - windowSize; i <= aLeftBoundary + windowSize; i++) {
			counter++;
			averageHeightLeftSide = aSpectrum.real(Math.round(i));
		}
		averageHeightLeftSide = averageHeightLeftSide / counter;

		//The middle of the window is the left boundary. The window size is 5 points
		counter = 0;
		for (i = aRightBoundary - windowSize; i <= aRightBoundary + windowSize; i++) {
			counter++;
			averageHeightRightSide = aSpectrum.real(Math.round(i));
		}
		averageHeightRightSide = averageHeightRightSide / counter;

		result.aLeftBoundaryX = aLeftBoundary;
		result.aLeftBoundaryY = averageHeightLeftSide;
		result.aRightBoundaryX = aRightBoundary;
		result.aRightBoundaryY = averageHeightRightSide;

		return result;
	};

	SpectrumQuality_Engine.prototype.getHeightLocalBaselineCorrection = function (aX, aLeftBoundaryX, aLeftBoundaryY, aRightBoundaryX, aRightBoundaryY) {

		var y;

		//We get the equation of the straight line give these two points: A(aLeftBoundary, averageHeightLeftSide) B(aRightBoundary, averageHeightRightSide);
		//The equation will be given by the following expression: Y = y1 + (X-x1)(y2-y1) / (x2-x1))
		y = aLeftBoundaryY + (((aX - aLeftBoundaryX) * (aRightBoundaryY - aLeftBoundaryY)) / (aRightBoundaryX - aLeftBoundaryX));

		return y;
	};

	SpectrumQuality_Engine.prototype.getWidthAtHeight = function (aSpectrum, aPeak, aHeightAt) {

		var result, pointsLocalBaseline, a, k, topHeightPPM, kPeakMax, kMax, kMin, w, xLeft, xRight, aux, width, N, SW, baselineHeightK, baselineHeightK_1;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";

		//Get initial values
		a = (aHeightAt / 100) * aPeak.intensity;
		topHeightPPM = aPeak.delta;
		N = Number(aSpectrum.getParam("Spectral Size"));
		SW = Number(aSpectrum.getParam("Spectral Width"));

		if (isNaN(N)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log += "\n\t\tThe Spectral Size parameter is not a number";
		}
		if (isNaN(SW)) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log += "\n\t\tThe Spectral Width parameter is not a number";
		}

		if (result.status === SpectrumQuality_Engine.status.PASSED) {

			//Set the both left and right boundary of the peak
			kPeakMax = Math.round(aSpectrum.unitsToUnits("ppm", "pt", topHeightPPM, 1));
			aux = aSpectrum.unitsToUnits("ppm", "hz", topHeightPPM, 1) - this.limitPeakInHz;
			kMax = Math.round(aSpectrum.unitsToUnits("hz", "pt", aux, 1));
			aux = aSpectrum.unitsToUnits("ppm", "hz", topHeightPPM, 1) + this.limitPeakInHz;
			kMin = Math.round(aSpectrum.unitsToUnits("hz", "pt", aux, 1));

			pointsLocalBaseline = this.getPointsLocalBaselineCorrection(aSpectrum, kMax, kMin);

			//Check for low points issue inside the peak
			if (Math.abs(kPeakMax - kMin) < 1) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log += "\n\t\tAt least two points are needed to the left of the highest point of the peak in order to calculate the peak width";
			}
			if (Math.abs(kMax - kPeakMax) < 1) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log += "\n\t\tAt least two points are needed to the right of the highest point of the peak in order to calculate the peak width";
			}

			if (result.status === SpectrumQuality_Engine.status.PASSED) {

				//LEFT SIDE Peak LineWidth Calculation. Get left point of the peak by using linear interpolation
				for (k = kPeakMax; k >= kMin; k--) {
					baselineHeightK = aSpectrum.real(k) - (this.getHeightLocalBaselineCorrection(k, pointsLocalBaseline.aLeftBoundaryX, pointsLocalBaseline.aLeftBoundaryY, pointsLocalBaseline.aRightBoundaryX, pointsLocalBaseline.aRightBoundaryY));
					if (baselineHeightK < a) {
						break;
					}
				}
				baselineHeightK = aSpectrum.real(k) - (this.getHeightLocalBaselineCorrection(k, pointsLocalBaseline.aLeftBoundaryX, pointsLocalBaseline.aLeftBoundaryY, pointsLocalBaseline.aRightBoundaryX, pointsLocalBaseline.aRightBoundaryY));
				baselineHeightK_1 = aSpectrum.real(k + 1) - (this.getHeightLocalBaselineCorrection((k + 1), pointsLocalBaseline.aLeftBoundaryX, pointsLocalBaseline.aLeftBoundaryY, pointsLocalBaseline.aRightBoundaryX, pointsLocalBaseline.aRightBoundaryY));
				if (a - baselineHeightK < baselineHeightK_1 - a) {
					w = (a - baselineHeightK) / (baselineHeightK_1 - a);
					xLeft = k + w / (1 + w);
				} else {
					w = (baselineHeightK_1 - a) / (a - baselineHeightK);
					xLeft = k + 1 / (1 + w);
				}

				//Check bad values for interpolation
				if (!((baselineHeightK) < a && (a < baselineHeightK_1))) {
					result.log += "\n\t\tThe height is not within the range formed by the two points using during the linear interpolation at left side of the peak";
				}

				//RIGHT SIDE Peak LineWidth Calculation. Get right point of the peak by using linear interpolation
				for (k = kPeakMax; k <= kMax; k++) {
					baselineHeightK = aSpectrum.real(k) - (this.getHeightLocalBaselineCorrection(k, pointsLocalBaseline.aLeftBoundaryX, pointsLocalBaseline.aLeftBoundaryY, pointsLocalBaseline.aRightBoundaryX, pointsLocalBaseline.aRightBoundaryY));
					if (baselineHeightK < a) {
						break;
					}
				}
				k--;
				baselineHeightK = aSpectrum.real(k) - (this.getHeightLocalBaselineCorrection(k, pointsLocalBaseline.aLeftBoundaryX, pointsLocalBaseline.aLeftBoundaryY, pointsLocalBaseline.aRightBoundaryX, pointsLocalBaseline.aRightBoundaryY));
				baselineHeightK_1 = aSpectrum.real(k + 1) - (this.getHeightLocalBaselineCorrection((k + 1), pointsLocalBaseline.aLeftBoundaryX, pointsLocalBaseline.aLeftBoundaryY, pointsLocalBaseline.aRightBoundaryX, pointsLocalBaseline.aRightBoundaryY));
				if (baselineHeightK - a < a - baselineHeightK_1) {
					w = (baselineHeightK - a) / (a - baselineHeightK_1);
					xRight = k + w / (1 + w);
				} else {
					w = (a - baselineHeightK_1) / (baselineHeightK - a);
					xRight = k + 1 / (1 + w);
				}

				//Check bad values for interpolation
				if (!((baselineHeightK) > a && (a > baselineHeightK_1))) {
					result.log += "\n\t\tThe height is not within the range formed by the two points using during the linear interpolation at right side of the peak";
				}

				//Width determination
				width = xRight - xLeft;
				result.width = width * SW / N;
				result.left = kMin;
				result.right = kMax;
				result.delta = topHeightPPM;

				if (result.status === SpectrumQuality_Engine.status.FAILED || result.status === SpectrumQuality_Engine.status.UNTESTED) {
					result.log = "\n\t[WARNING]: There was a problem during the peak width calculation at " + aHeightAt + " % height:" + result.log;
				}
			}
		} else {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log = "\n\t[ERROR]: The peak width calculation at " + aHeightAt + "% height has not been possible because of the following reasons:" + result.log;
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.getSkewness = function (aSpectrum, aLeftBoundary, aRightBoundary) {

		var k, skewness, averageNumerator, averageDenominator, weightedAverage, intensity,
			frequency, m3, s3, m3Numerator, m3Denominator, s3Numerator, s3Denominator, auxs3;

		//To calculate the skewness we use the third moments by using the estimator of the population skewness: sk = (m3)^3 / (s3)^3/2
		//Well, x(i) is just a measurement of distributed value.
		//First, x(average) should be replaced with sum(f(i)*I(i))/sum(I(i)) where f(i) - is the frequency and I(i) - intensity of the i-point.
		//m3 = sum(I(i)*(f(i) - average)^3) / sum(I(i)) where "average" is from above
		//s3 = (sum(I(i)*(f(i) - average)^2) / sum(I(i)))^3/2 where "average" is from above
		averageNumerator = 0;
		averageDenominator = 0;

		//We calculate the weighted average by intensities
		for (k = aLeftBoundary; k <= aRightBoundary; k++) {
			frequency = aSpectrum.unitsToUnits("pt", "hz", k, 1);
			intensity = aSpectrum.real(k);
			averageNumerator += (frequency * intensity);
			averageDenominator += intensity;
		}
		weightedAverage = averageNumerator / averageDenominator;

		//It calculates the third moments m3 and numerator of s3
		m3Numerator = 0;
		m3Denominator = averageDenominator;
		s3Numerator = 0;
		for (k = aLeftBoundary; k <= aRightBoundary; k++) {
			frequency = aSpectrum.unitsToUnits("pt", "hz", k, 1);
			intensity = aSpectrum.real(k);
			m3Numerator += intensity * (Math.pow((frequency - weightedAverage), 3));
			s3Numerator += intensity * (Math.pow((frequency - weightedAverage), 2));
		}
		m3 = m3Numerator / m3Denominator;

		//It calculates s3 standard deviation
		s3Denominator = averageDenominator;
		auxs3 = s3Numerator / s3Denominator;
		s3 = Math.pow(auxs3, (3 / 2));

		//Finally, it gets the skewness
		skewness = m3 / s3;

		return skewness;
	};

	SpectrumQuality_Engine.prototype.lineSymmetry = function (aSpectrum, aDelta, aRightBoundary, aLeftBoundary) {

		var k, skewness, lineSlope, differenceXAxis, noise, centrePoint,
			verticalBaselineOffset, leftBoundary, rightBoundary, auxBoundary;

		//Check size limits
		if (aLeftBoundary > aRightBoundary) {
			auxBoundary = aRightBoundary;
			aRightBoundary = aLeftBoundary;
			aLeftBoundary = auxBoundary;
		}

		//Get the noise and slope for calculation
		noise = aSpectrum.getNoise();
		differenceXAxis = aRightBoundary - aLeftBoundary;
		lineSlope = (aSpectrum.real(aRightBoundary) - aSpectrum.real(aLeftBoundary)) / (differenceXAxis);
		centrePoint =  Math.round(aSpectrum.unitsToUnits("ppm", "pt", aDelta, 1));
		leftBoundary = Math.round(aLeftBoundary);
		rightBoundary = Math.round(aRightBoundary);

		//Look for the left limit
		for (k = (centrePoint - 1); k >= aLeftBoundary; k--) {
			verticalBaselineOffset = (k - aLeftBoundary) * lineSlope + aSpectrum.real(aLeftBoundary);
			if (aSpectrum.real(k) < 3 * noise + verticalBaselineOffset) {
				leftBoundary = k;
				break;
			}
		}

		//Look for the right limit
		for (k = (centrePoint + 1); k <= aRightBoundary; k++) {
			verticalBaselineOffset = (k - aLeftBoundary) * lineSlope + aSpectrum.real(aLeftBoundary);
			if (aSpectrum.real(k) < 3 * noise + verticalBaselineOffset) {
				rightBoundary = k;
				break;
			}
		}

		//Check for the the correct order
		if (leftBoundary > rightBoundary) {
			auxBoundary = rightBoundary;
			rightBoundary = leftBoundary;
			leftBoundary = auxBoundary;
		}

		//It gets the skewness of the peak region
		skewness = this.getSkewness(aSpectrum, leftBoundary, rightBoundary);

		return skewness;
	};

	SpectrumQuality_Engine.prototype.processPeakWidth = function (aSpectrum, aPeakType, aPeakHeightAt, aPeakCondition, aPeakValue, aWidthDecimals, aFullSpectrum, aFromPPM, aToPPM, aAsymmetryTestCondition, aAsymmetryTestValue, aDocument) {

		var result, multipletList, multipletAnalysis, peakList,
			extremPeak, auxResult, spectrumLimits, skewness,
			currentMultipletLabelValue, currentIntegralValue;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";

		//Get multiplets because we work with the peaks obtained trough this analysis
		multipletList = aSpectrum.multiplets();
		if (multipletList.count === 0) {

			//Get current values to be restored later due to bug #18008
			currentMultipletLabelValue = aSpectrum.getProperty("multiplets.show");
			currentIntegralValue = aSpectrum.getProperty("integrals.show");

			//Get processing instance from spectrum
			multipletAnalysis = new NMRProcessing(aSpectrum.proc);

			//Changes the default PP in order to ensure that the implicit peak peaking carried out by the multiplet analysis is GSD
			multipletAnalysis.setParameter("PP.Apply", false);
			multipletAnalysis.setParameter("PP.Method", "GSD");
			aSpectrum.process(multipletAnalysis);

			//This workaround lets to carry out a new multiplet analysis by using the same algorithm if it was performed previously. Bug http://192.168.2.22/redmine/issues/10506
			multipletAnalysis.setParameter("Mult.Apply", false);
			aSpectrum.process(multipletAnalysis);

			//Now, we perform the multiplet analysis by ensuring that it will carry it out
			multipletAnalysis.setParameter("Mult.Apply", true);
			if (aSpectrum.process(multipletAnalysis)) {
				aSpectrum.update();
				aDocument.update();

			} else {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log = "\n\t[ERROR]: Basic multiplet analysis was carried out with errors";
			}
		}

		//At this point we must have at least a peak
		multipletList = aSpectrum.multiplets();
		if (multipletList.count === 0) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log += "\n\t[WARNING]: The spectrum does not have at least a multiplet which is needed to carry on this peak width test";
		} else {

			//Get the extreme peak
			peakList = aSpectrum.peaks();
			extremPeak = this.findIsolatedPeak(multipletList, peakList, aPeakType, aFullSpectrum, aFromPPM, aToPPM);

			//Ensure we have at least a peak within the region
			if (extremPeak !== undefined) {
				auxResult = this.getWidthAtHeight(aSpectrum, extremPeak, aPeakHeightAt);
				extremPeak.width = auxResult.width;
				extremPeak.left = auxResult.left;
				extremPeak.right = auxResult.right;
				extremPeak.delta = auxResult.delta;

				//Check for possible errors
				if (auxResult.status === SpectrumQuality_Engine.status.FAILED) {
					result.status = SpectrumQuality_Engine.status.FAILED;
					result.log += auxResult.log;
				} else if (auxResult.status === SpectrumQuality_Engine.status.UNTESTED) {
					result.log += auxResult.log;
				} else if (extremPeak.width === undefined) {
					result.status = SpectrumQuality_Engine.status.UNTESTED;
					result.log += auxResult.log;
				}

				//Evaluate the condition only if the peak line width has a number
				if (extremPeak.width !== undefined && !isNaN(extremPeak.width)) {

					//Set the number of decimals
					if (extremPeak.intensity !== undefined && !isNaN(extremPeak.intensity)) {
						extremPeak.intensity = extremPeak.intensity.toFixed(aWidthDecimals);
					}
					if (extremPeak.width !== undefined && !isNaN(extremPeak.width)) {
						extremPeak.width = extremPeak.width.toFixed(aWidthDecimals);
					}
					if (extremPeak.delta !== undefined && !isNaN(extremPeak.delta)) {
						extremPeak.delta = extremPeak.delta.toFixed(aWidthDecimals);
					}

					//Checking for peaks inside the interval
					if (extremPeak.intensity === undefined) {
						result.status = SpectrumQuality_Engine.status.UNTESTED;
						spectrumLimits = aSpectrum.getFullScaleLimits();
						if (this.checkIsInsideTheLimits(aFromPPM, aToPPM, spectrumLimits.fromX, spectrumLimits.toX)) {
							if (aPeakType === "Any") {
								result.log += "\n\t[WARNING]: No peak was found in the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
							} else {
								result.log += "\n\t[WARNING]: No peak of type: " + aPeakType + " was found in the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
							}
						} else {
							result.log += "\n\t[WARNING]: The range region: [" + aFromPPM + ", " + aToPPM + "] is out of the spectrum bounds: [" + spectrumLimits.fromX + ", " + spectrumLimits.toX + "]";
						}
					} else {

						//Get information about the peak
						if (aPeakType === "Any") {
							result.log += "\n\t[INFO]: Peak at " + extremPeak.delta + " ppm";
						} else {
							result.log += "\n\t[INFO]: Peak at " + extremPeak.delta + " ppm of type: " + aPeakType;
						}
						result.log += "\n\t[INFO]: At " + aPeakHeightAt + "% of peak height the width is " + extremPeak.width + " Hz";

						//Perform the line symmetry test
						skewness = this.lineSymmetry(aSpectrum, extremPeak.delta, extremPeak.left, extremPeak.right);
						if (skewness !== undefined && !isNaN(skewness)) {

							//It prints the skewness value
							result.log += "\n\t[INFO]: Skewness value for auxiliary asymmetry test: " + skewness;

							//Evaluate the condition and manage the result if there is a threshold
							if (this.peakAsymmetryValue !== undefined && !isNaN(this.peakAsymmetryValue) && this.peakAsymmetryCondition !== undefined && this.peakAsymmetryCondition !== "") {
								auxResult = this.evaluateCondition(skewness, aAsymmetryTestCondition, aAsymmetryTestValue);
								result.status = auxResult.status;
								if (result.status === SpectrumQuality_Engine.status.FAILED) {
									result.log += "\n\t[WARNING]: The auxiliary asymmetry test does not meet the condition: " + auxResult.condition;
								} else if (this.debugMode !== undefined && this.debugMode) {
									result.log += "\n\t[INFO]: The auxiliary asymmetry test meets the condition: " + auxResult.condition;
								}
							}
						} else {
							result.log += "\n\t[WARNING]: The skewness value for auxiliary asymmetry is not a number";
						}

						//Evaluate the condition and manage the result if there is a threshold
						if (this.peakValue !== undefined && !isNaN(this.peakValue) && this.peakCondition !== undefined && this.peakCondition !== "") {
							auxResult = this.evaluateCondition(extremPeak.width, aPeakCondition, aPeakValue);
							result.status = auxResult.status;
							if (result.status === SpectrumQuality_Engine.status.FAILED) {
								result.log += "\n\t[WARNING]: The peak does not meet the condition: " + auxResult.condition;
							} else if (this.debugMode !== undefined && this.debugMode) {
								result.log += "\n\t[INFO]: The peak meets the condition: " + auxResult.condition;
							}
						}
					}
				} else {
					result.status = SpectrumQuality_Engine.status.UNTESTED;
					result.log += "\n\t[ERROR]: The peak width value obtained is not a number";
				}
			} else {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				if (aPeakType === "Any") {
					result.log += "\n\t[WARNING]: No suitable peak was found to perform the measurement inside the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
				} else {
					result.log += "\n\t[WARNING]: No suitable peak of type: " + aPeakType + " was found to perform the measurement inside the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
				}
			}

			//Restore multiplet labels view due to the bug #18008
			if (currentMultipletLabelValue !== undefined) {
				if (typeof (currentMultipletLabelValue) === "boolean") {
					if (aSpectrum !== undefined && aSpectrum.uuid !== undefined) {
						if (aSpectrum.uuid !== "" && aSpectrum.isValid()) {
							aSpectrum.setProperty("multiplets.show", currentMultipletLabelValue);
						}
					}
				}
			}

			//Restore integrals view due to the bug #18008
			if (currentIntegralValue !== undefined) {
				if (typeof (currentIntegralValue) === "boolean") {
					if (aSpectrum !== undefined && aSpectrum.uuid !== undefined) {
						if (aSpectrum.uuid !== "" && aSpectrum.isValid()) {
							aSpectrum.setProperty("integrals.show", currentIntegralValue);
						}
					}
				}
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.processIntensity = function (aSpectrum, aIntensityPeakType, aIntensityCondition, aIntensityValue, aWidthDecimals, aFullSpectrum, aFromPPM, aToPPM, aDocument) {

		var result, peakList, peakPicking, peak, auxResult, spectrumLimits;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";

		//Delete previous peaks
		if (this.clearPeaksBeforStartingEachProcess !== undefined && this.clearPeaksBeforStartingEachProcess) {
			aSpectrum.peaks().clear();
		}

		//Get peak list and force a peak picking process if there is no at least one peak
		peakList = aSpectrum.peaks();
		if (peakList.count === 0) {

			//Get processing object to perform a peak picking
			peakPicking = new NMRProcessing(aSpectrum.proc);

			//This workaround lets to carry out a new Peak Picking process by using the same PP algorithm. Bug http://192.168.2.22/redmine/issues/10506
			peakPicking.setParameter("PP.Apply", false);
			peakPicking.setParameter("PP.Method", "GSD");
			peakPicking.setParameter("PP.AutoClassify", false);
			aSpectrum.process(peakPicking);
			peakPicking.setParameter("PP.Apply", true);
			peakPicking.setParameter("PP.Method", "GSD");

			//For better performance we disable qQSD because SQA does not need qGSD peak picking results
			//Regular GSD results are good enough.
			peakPicking.setParameter("PP.GSD.qGSDApply", false);

			//We need to perform the auto classify option
			//Otherwise SQA will show 100% as purity value every time because it sets all peak types to "Compound"
			//Therefore, there are no impurities. Hence, we need to auto-classify peaks for the spectrum
			peakPicking.setParameter("PP.AutoClassify", true);

			//If the peak picking was fine, we show the peaks
			//Otherwise, an error will be recollected
			if (aSpectrum.process(peakPicking)) {
				aSpectrum.setProperty("peaks.show", false);
				aSpectrum.update();
				aDocument.update();
			} else {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log = "[WARNING]: The peak picking process was carried out with errors";
			}
		}

		//At this point we must have at least a peak
		if (peakList.count === 0) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log = "\n\t[ERROR]: The peak intensity test cannot be determined because there are no peaks according to the established parameters";
		} else {
			//Get the extreme peak
			peakList = aSpectrum.peaks();
			peak = this.findPeak(peakList, aIntensityPeakType, aFullSpectrum, aFromPPM, aToPPM);

			//Ensure we have at least a peak within the region
			if (peak !== undefined) {

				//Evaluate the condition only if the peak line widht has a number
				if (peak.intensity !== undefined && !isNaN(peak.intensity)) {

					//Set the number of decimals
					if (peak.intensity !== undefined && !isNaN(peak.intensity)) {
						peak.intensity = peak.intensity.toFixed(aWidthDecimals);
					}
					if (peak.delta !== undefined && !isNaN(peak.delta)) {
						peak.delta = peak.delta.toFixed(aWidthDecimals);
					}

					//Checking for peaks inside the interval
					if (peak.intensity === undefined) {
						result.status = SpectrumQuality_Engine.status.UNTESTED;
						spectrumLimits = aSpectrum.getFullScaleLimits();
						if (this.checkIsInsideTheLimits(aFromPPM, aToPPM, spectrumLimits.fromX, spectrumLimits.toX)) {
							if (aIntensityPeakType === "Any") {
								result.log += "\n\t[WARNING]: No peak was found in the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
							} else {
								result.log += "\n\t[WARNING]: No peak of type: " + aIntensityPeakType + " was found in the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
							}
						} else {
							result.log += "\n\t[WARNING]: The range region: [" + aFromPPM + ", " + aToPPM + "] is out of the spectrum bounds: [" + spectrumLimits.fromX + ", " + spectrumLimits.toX + "]";
						}
					} else {

						//Get information about the peak
						if (aIntensityPeakType === "Any") {
							result.log += "\n\t[INFO]: Peak at " + peak.delta + " ppm";
						} else {
							result.log += "\n\t[INFO]: Peak at " + peak.delta + " ppm of type: " + aIntensityPeakType;
						}
						result.log += "\n\t[INFO]: The intensity of the peak is " + peak.intensity;

						//Evaluate the condition and manage the result if there is a threshold
						if (this.peakIntensityValue !== undefined && !isNaN(this.peakIntensityValue) && this.peakIntensityCondition !== undefined && this.peakIntensityCondition !== "") {
							auxResult = this.evaluateCondition(peak.intensity, aIntensityCondition, aIntensityValue);
							result.status = auxResult.status;
							if (result.status === SpectrumQuality_Engine.status.FAILED) {
								result.log += "\n\t[WARNING]: The peak does not meet the condition: " + auxResult.condition;
							} else if (this.debugMode !== undefined && this.debugMode) {
								result.log += "\n\t[INFO]: The peak meets the condition: " + auxResult.condition;
							}
						}
					}
				} else {
					result.status = SpectrumQuality_Engine.status.UNTESTED;
					result.log += "\n\t[ERROR]: The peak intensity value obtained is not a number";
				}
			} else {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				if (aIntensityPeakType === "Any") {
					result.log += "\n\t[WARNING]: No suitable peak was found to perform the measurement inside the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
				} else {
					result.log += "\n\t[WARNING]: No suitable peak of type: " + aIntensityPeakType + " was found to perform the measurement inside the ppm region: [" + aFromPPM + ", " + aToPPM + "]";
				}
			}
		}

		return result;
	};

	SpectrumQuality_Engine.prototype.processPurity = function (aSpectrum, aDocument, aPurityCondition, aPurityValue) {

		var result, peakList, peakPicking, purity, resultCondition;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";

		//Delete previous peaks
		if (this.clearPeaksBeforStartingEachProcess !== undefined && this.clearPeaksBeforStartingEachProcess) {
			aSpectrum.peaks().clear();
		}

		//Get peak list and force a peak picking process if there is no at least one peak
		peakList = aSpectrum.peaks();
		if (peakList.count === 0) {

			//Get processing object to perform a peak picking
			peakPicking = new NMRProcessing(aSpectrum.proc);

			//This workaround lets to carry out a new Peak Picking process by using the same PP algorithm. Bug http://192.168.2.22/redmine/issues/10506
			peakPicking.setParameter("PP.Apply", false);
			peakPicking.setParameter("PP.Method", "GSD");
			peakPicking.setParameter("PP.AutoClassify", false);
			aSpectrum.process(peakPicking);
			peakPicking.setParameter("PP.Apply", true);
			peakPicking.setParameter("PP.Method", "GSD");

			//For better performance we disable qQSD because SQA does not need qGSD peak picking results
			//Regular GSD results are good enough.
			peakPicking.setParameter("PP.GSD.qGSDApply", false);

			//We need to perform the auto classify option
			//Otherwise SQA will show 100% as purity value every time because it sets all peak types to "Compound"
			//Therefore, there are no impurities. Hence, we need to auto-classify peaks for the spectrum
			peakPicking.setParameter("PP.AutoClassify", true);

			//If the peak picking was fine, we show the peaks
			//Otherwise, an error will be recollected
			if (aSpectrum.process(peakPicking)) {
				aSpectrum.setProperty("peaks.show", false);
				aSpectrum.update();
				aDocument.update();
			} else {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log = "[WARNING]: The peak picking process was carried out with errors";
			}
		}

		//At this point we must have at least a peak
		purity = aSpectrum.calcPeaksPurity();
		if (peakList.count === 0) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log = "\n\t[ERROR]: Unable to determine the purity based on the peak types due to no peaks exist";
		} else {
			if (isNaN(purity)) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log += "\n\t[ERROR]: Unable to determine the purity based on the peak types because of the returned value is not a valid number";
			} else {
				purity = Number(purity * 100).toFixed(this.defaultDecimalsPrecision);
				result.log += "\n\t[INFO]: The purity based on the peak types is: " + purity + "%";
				if (aPurityCondition !== undefined && aPurityCondition !== "" && aPurityValue !== undefined && !isNaN(aPurityValue)) {
					resultCondition = this.evaluateCondition(purity, aPurityCondition, aPurityValue);
					result.status = resultCondition.status;
					if (result.status === SpectrumQuality_Engine.status.FAILED) {
						result.log = "\n\t[WARNING]: The purity test does not meet the condition: " + resultCondition.condition;
					} else if (this.debugMode !== undefined && this.debugMode) {
						result.log = "\n\t[INFO]: The purity test meets the condition: " + resultCondition.condition;
					}
				}
			}
		}

		return result;

	};

	SpectrumQuality_Engine.prototype.processDigitalResolution = function (aSpectrum, aDigitalResolutionCondition, aDigitalResolutionValue) {

		var result, digitalResolution, resultCondition;

		result = {};
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "";

		//Get digital resolution from the parameters table
		digitalResolution = aSpectrum.getParam("Digital Resolution");
		if (digitalResolution === "" || digitalResolution === undefined) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log = "\n\t[ERROR]: Unable to obtain the digital resolution from the parameters table";
		} else {
			if (isNaN(digitalResolution)) {
				result.status = SpectrumQuality_Engine.status.UNTESTED;
				result.log += "\n\t[ERROR]: Unable to determine the digital resolution because of the returned value is not a valid number";
			} else {
				digitalResolution = Number(digitalResolution).toFixed(this.defaultDecimalsPrecision);
				result.log += "\n\t[INFO]: The digital resolution is: " + digitalResolution + "Hz/pt";
				if (aDigitalResolutionCondition !== undefined && aDigitalResolutionCondition !== "" && aDigitalResolutionValue !== undefined && !isNaN(aDigitalResolutionValue)) {
					resultCondition = this.evaluateCondition(digitalResolution, aDigitalResolutionCondition, aDigitalResolutionValue);
					result.status = resultCondition.status;
					if (result.status === SpectrumQuality_Engine.status.FAILED) {
						result.log = "\n\t[WARNING]: The digital resolution test does not meet the condition: " + resultCondition.condition;
					} else if (this.debugMode !== undefined && this.debugMode) {
						result.log = "\n\t[INFO]: The digital resolution test meets the condition: " + resultCondition.condition;
					}
				}
			}
		}

		return result;

	};

	SpectrumQuality_Engine.prototype.process = function (aSpectrum) {

		var i, result, document, auxResult, auxResult2, auxZoom, auxView, properties, parameter, auxLog,
			flagPeakWidthChecked, flagPeakWidthUntested, flagPreviousPeaks, flagPreviousMultiplets, flagPeakPicking,
			peakWidthTotalParameters, flagIntensityChecked, flagIntensityUntested, intensityTotalParameters, intensityTest,
			flagIntensity, flagTestFailedOrPassed, flagTestPerformed, auxStringResult, peakWidthTest, flagPeakWidth, spectrumTitle,
			flagUseCurrentAnalysis, flagOriginalSpectrum, processingTemplate, currentPeakPickingState, spectrum, currentPeakPickingMethod,
			currentPeakPickingqQSD, currentPeakPickingAutoClassify, hiddenSpectrum, hiddenDocument, flagHiddenDocument, flagCloneHiddenSpectrum,
			optionNameInViewerEnabled, optionNameInViewerDisabled;

		//Initialize vars
		auxLog = "";
		result = {};
		document = mainWindow.activeDocument;
		result.status = SpectrumQuality_Engine.status.PASSED;
		result.log = "[INFO]: Quality test started on " + this.getCurrentDate();
		spectrum = aSpectrum;
		flagPreviousPeaks = false;
		flagPeakPicking = false;
		flagOriginalSpectrum = true;
		flagUseCurrentAnalysis = false;

		//Check critical errors
		if ((spectrum === undefined) || (spectrum.name !== "NMR Spectrum") || !(spectrum.isValid())) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log += "\n[ERROR]: The spectrum is not valid";
			return result;
		}

		if (spectrum.dimCount === 2) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log += "\n[ERROR]: Only 1D spectrum is allowed";
			return result;
		}

		//Flags realted to previous analysis
		flagPreviousPeaks = spectrum.peaks().count > 0;
		flagPreviousMultiplets = spectrum.multiplets().count > 0;

		//Checking to know if we use the original or a background copy of the spectrum
		if (this.performSQAUsingSpectrumCopyInHiddenDocument !== undefined && this.performSQAUsingSpectrumCopyInHiddenDocument) {
			flagHiddenDocument = false;
			flagCloneHiddenSpectrum = false;
			hiddenDocument = this.cloneSpectrumInHiddenDocument(spectrum);
			if (hiddenDocument !== undefined) {
				if (hiddenDocument.uuid !== undefined && hiddenDocument.uuid !== "") {
					if (hiddenDocument.isValid()) {
						flagHiddenDocument = true;
						hiddenSpectrum = hiddenDocument.item(0, "NMR Spectrum");
						if (hiddenSpectrum !== undefined) {
							if (hiddenSpectrum.uuid !== undefined && hiddenSpectrum.uuid !== "") {
								if (hiddenSpectrum.isValid()) {
									spectrum = new NMRSpectrum(hiddenSpectrum);
									flagCloneHiddenSpectrum = true;
									flagOriginalSpectrum = false;
									document = hiddenDocument;
								}
							}
						}
					}
				}
			}
		}

		spectrumTitle = spectrum.title;

		if (this.badParametersPath !== undefined && this.badParametersPath) {
			result.status = SpectrumQuality_Engine.status.UNTESTED;
			result.log += "\n[ERROR]: The file path which contains the parameters does not exist";
			return result;
		}

		//This only makes sense with the original spectrum.
		//Get previous zoom, view and several options
		if (flagOriginalSpectrum) {
			auxZoom = spectrum.getScaleLimits();
			auxView = spectrum.getProperty("peaks.show");

			//Get current Peak Picking values to be restored later (bug #18008)
			if (spectrum.proc !== undefined) {
				processingTemplate = spectrum.proc;
				currentPeakPickingState = processingTemplate.getParameter("PP.Apply");
				currentPeakPickingMethod = processingTemplate.getParameter("PP.Method");
				if (currentPeakPickingMethod === "GSD") {
					currentPeakPickingqQSD = processingTemplate.getParameter("PP.GSD.qGSDApply");
				}
				currentPeakPickingAutoClassify = processingTemplate.getParameter("PP.AutoClassify");
			}
		}

		//Take into account user analysis
		if (!this.clearPeaksBeforStartingEachProcess && !this.deletePreviousPeaksAtSNR) {
			flagUseCurrentAnalysis = true;
		}

		//Check quality regarding the acquisition parameters
		auxResult = this.processParameters(this.acquisitionParameters, spectrum, true, this.handleBlankSpaceAsNumericValueInConditionForAcquisitionParametersTest);
		result.acquisitionParametersTest = {};
		if (auxResult.used) {
			switch (auxResult.status) {
			case SpectrumQuality_Engine.status.FAILED:
				result.status = SpectrumQuality_Engine.status.FAILED;
				result.acquisitionParametersTest.status = SpectrumQuality_Engine.status.FAILED;
				auxStringResult = "\n[WARNING]: Acquisition parameter test(s): FAILED";
				auxLog += auxStringResult + auxResult.log;
				flagTestFailedOrPassed = true;
				break;
			case SpectrumQuality_Engine.status.PASSED:
				auxStringResult = "\n[INFO]: Acquisition parameter test(s): PASSED";
				auxLog += auxStringResult;
				if (this.debugMode !== undefined && this.debugMode) {
					auxLog += auxResult.log;
					flagTestFailedOrPassed = true;
				}
				result.acquisitionParametersTest.status = SpectrumQuality_Engine.status.PASSED;
				break;
			case SpectrumQuality_Engine.status.UNTESTED:
				auxStringResult = "\n[WARNING]: Acquisition parameter test(s): UNTESTED";
				auxLog += auxStringResult + auxResult.log;
				result.acquisitionParametersTest.status = SpectrumQuality_Engine.status.UNTESTED;
				break;
			}
			result.acquisitionParametersTest.desc = auxStringResult + auxResult.log;
		} else {
			result.acquisitionParametersTest.status = SpectrumQuality_Engine.status.NOT_USED;
			result.acquisitionParametersTest.desc = "\n[INFO]: The acquisition parameter test has not been enabled";
		}

		//Check quality regarding the processing parameters
		auxResult = this.processParameters(this.processingParameters, spectrum, false, this.handleBlankSpaceAsNumericValueInConditionForProcessingParametersTest);
		result.processingParametersTest = {};
		if (auxResult.used) {
			switch (auxResult.status) {
			case SpectrumQuality_Engine.status.FAILED:
				result.status = SpectrumQuality_Engine.status.FAILED;
				result.processingParametersTest.status = SpectrumQuality_Engine.status.FAILED;
				auxStringResult = "\n[WARNING]: Processing parameter test(s): FAILED";
				auxLog += auxStringResult + auxResult.log;
				flagTestFailedOrPassed = true;
				break;
			case SpectrumQuality_Engine.status.PASSED:
				auxStringResult = "\n[INFO]: Processing parameter test(s): PASSED";
				auxLog += auxStringResult;
				if (this.debugMode !== undefined && this.debugMode) {
					auxLog += auxResult.log;
					flagTestFailedOrPassed = true;
				}
				result.processingParametersTest.status = SpectrumQuality_Engine.status.PASSED;
				break;
			case SpectrumQuality_Engine.status.UNTESTED:
				auxStringResult = "\n[WARNING]: Processing parameter test(s): UNTESTED";
				auxLog += auxStringResult + auxResult.log;
				result.processingParametersTest.status = SpectrumQuality_Engine.status.UNTESTED;
				break;
			}
			result.processingParametersTest.desc = auxStringResult + auxResult.log;
		} else {
			result.processingParametersTest.status = SpectrumQuality_Engine.status.NOT_USED;
			result.processingParametersTest.desc = "\n[INFO]: The processing parameter test has not been enabled";
		}

		//Check quality regarding the SNR
		result.signalToNoiseTest = {};
		if (this.signalToNoiseFilterStatus !== undefined && this.signalToNoiseFilterStatus) {
			auxResult = this.snrParametersValidation();
			if (auxResult.status === SpectrumQuality_Engine.status.PASSED) {
				auxResult = this.processSNR(spectrum, this.signalFullSpectrum, this.signalFrom, this.signalTo, this.noiseAutomatic, this.noiseFrom, this.noiseTo, this.snrMinValue, document);
				flagPeakPicking = true;
				switch (auxResult.status) {
				case SpectrumQuality_Engine.status.FAILED:
					result.status = SpectrumQuality_Engine.status.FAILED;
					result.signalToNoiseTest.status = SpectrumQuality_Engine.status.PERFORMED;
					flagTestPerformed = true;
					auxStringResult = "\n[WARNING]: SNR test:";
					if (this.snrMinValue !== undefined) {
						auxStringResult += " FAILED";
						flagTestFailedOrPassed = true;
						result.signalToNoiseTest.status = SpectrumQuality_Engine.status.FAILED;
					} else {
						auxStringResult += " PERFORMED";
					}
					auxLog += auxStringResult + auxResult.log;
					break;
				case SpectrumQuality_Engine.status.PASSED:
					result.signalToNoiseTest.status = SpectrumQuality_Engine.status.PERFORMED;
					auxStringResult = "\n[INFO]: SNR test:";
					flagTestPerformed = true;
					if (this.snrMinValue !== undefined) {
						auxStringResult += " PASSED";
						flagTestFailedOrPassed = true;
						result.signalToNoiseTest.status = SpectrumQuality_Engine.status.PASSED;
					} else {
						auxStringResult += " PERFORMED";
					}
					auxLog += auxStringResult;
					if (this.debugMode !== undefined && this.debugMode) {
						auxLog += auxResult.log;
					}
					break;
				case SpectrumQuality_Engine.status.UNTESTED:
					if (this.snrMinValue !== undefined) {
						auxStringResult = "\n[WARNING]: SNR test: UNTESTED";
						result.signalToNoiseTest.status = SpectrumQuality_Engine.status.UNTESTED;
					} else {
						auxStringResult = "\n[WARNING]: SNR test: NOT PERFORMED";
						result.signalToNoiseTest.status = SpectrumQuality_Engine.status.NOT_PERFORMED;
					}
					auxLog += auxStringResult + auxResult.log;
					break;
				}
			} else {
				auxStringResult = "\n[ERROR]: SNR test:";
				result.signalToNoiseTest.status = SpectrumQuality_Engine.status.NOT_PERFORMED;
				if (this.snrMinValue !== undefined) {
					auxStringResult += " UNTESTED";
					result.status = SpectrumQuality_Engine.status.UNTESTED;
					result.signalToNoiseTest.status = SpectrumQuality_Engine.status.UNTESTED;
				}
				auxLog += auxStringResult + auxResult.log;
			}
			result.signalToNoiseTest.desc = auxStringResult + auxResult.log;
		} else {
			result.signalToNoiseTest.status = SpectrumQuality_Engine.status.NOT_USED;
			result.signalToNoiseTest.desc = "\n[INFO]: The SNR test has not been enabled";
		}

		//Check quality regarding the phase error
		result.phaseErrorTest = {};
		if (this.phaseErrorFilterStatus !== undefined && this.phaseErrorFilterStatus) {
			auxResult = this.phaseErrorParametersValidation();
			if (auxResult.status === SpectrumQuality_Engine.status.PASSED) {
				auxResult = this.processPhaseError(spectrum, this.phaseErrorCondition, this.phaseErrorValue);
			} else {
				auxResult2 = this.processPhaseError(spectrum);
				if (auxResult2.status !== SpectrumQuality_Engine.status.PASSED) {
					auxResult = auxResult2;
				}
				auxResult.log += auxResult2.log;
			}
			switch (auxResult.status) {
			case SpectrumQuality_Engine.status.FAILED:
				result.status = SpectrumQuality_Engine.status.FAILED;
				result.phaseErrorTest.status = SpectrumQuality_Engine.status.PERFORMED;
				flagTestPerformed = true;
				auxStringResult = "\n[WARNING]: Phase Error test:";
				if (this.phaseErrorCondition !== undefined && this.phaseErrorValue !== undefined && this.phaseErrorCondition !== "") {
					auxStringResult += " FAILED";
					flagTestFailedOrPassed = true;
					result.phaseErrorTest.status = SpectrumQuality_Engine.status.FAILED;
				} else {
					auxStringResult += " PERFORMED";
				}
				auxLog += auxStringResult + auxResult.log;
				break;
			case SpectrumQuality_Engine.status.PASSED:
				result.phaseErrorTest.status = SpectrumQuality_Engine.status.PERFORMED;
				flagTestPerformed = true;
				auxStringResult = "\n[INFO]: Phase Error test:";
				if (this.phaseErrorCondition !== undefined && this.phaseErrorValue !== undefined && this.phaseErrorCondition !== "") {
					auxStringResult += " PASSED";
					flagTestFailedOrPassed = true;
					result.phaseErrorTest.status = SpectrumQuality_Engine.status.PASSED;
				} else {
					auxStringResult += " PERFORMED";
				}
				auxLog += auxStringResult;
				if (this.debugMode !== undefined && this.debugMode) {
					auxLog += auxResult.log;
				}
				break;
			case SpectrumQuality_Engine.status.UNTESTED:
				if (this.phaseErrorCondition !== undefined && this.phaseErrorValue !== undefined && this.phaseErrorCondition !== "") {
					auxStringResult = "\n[WARNING]: Phase Error test: UNTESTED";
					result.phaseErrorTest.status = SpectrumQuality_Engine.status.UNTESTED;
				} else {
					auxStringResult = "\n[WARNING]: Phase Error test: NOT PERFORMED";
					result.phaseErrorTest.status = SpectrumQuality_Engine.status.NOT_PERFORMED;
				}
				auxLog += auxStringResult + auxResult.log;
				break;
			}
			result.phaseErrorTest.desc = auxStringResult + auxResult.log;
		} else {
			result.phaseErrorTest.status = SpectrumQuality_Engine.status.NOT_USED;
			result.phaseErrorTest.desc = "\n[INFO]: The phase error test has not been enabled";
		}

		//Check quality regarding the peak width
		result.peakWidthTest = {};
		flagPeakWidthUntested = false;
		if (this.peakFilterStatus !== undefined && this.peakFilterStatus) {
			if (this.clearPeaksBeforStartingEachProcess !== undefined && this.clearPeaksBeforStartingEachProcess) {
				spectrum.peaks().clear();
				spectrum.multiplets().clear();
			}
			i = 0;
			peakWidthTotalParameters = this.getNumberOfPeakWidthTests(this.peakWidthParameters, "checked");
			for (properties in this.peakWidthParameters) {
				if (this.peakWidthParameters.hasOwnProperty(properties)) {
					i++;
					peakWidthTest = "test" + i;
					result.peakWidthTest[peakWidthTest] = {};
					if (!isNaN(properties)) {
						flagPeakWidthChecked = false;
						for (parameter in this.peakWidthParameters[properties]) {
							if (this.peakWidthParameters[properties].hasOwnProperty(parameter)) {
								if (parameter === "checked" && this.peakWidthParameters[properties][parameter]) {
									flagPeakWidthChecked = true;
								}
								switch (parameter) {
								case "fromPPM":
									this.peakFrom = this.peakWidthParameters[properties][parameter];
									break;
								case "toPPM":
									this.peakTo = this.peakWidthParameters[properties][parameter];
									break;
								case "peakType":
									this.peakType = this.peakWidthParameters[properties][parameter];
									break;
								case "atHeight":
									this.peakHeightAt = this.peakWidthParameters[properties][parameter];
									break;
								case "condition":
									this.peakCondition = this.peakWidthParameters[properties][parameter];
									break;
								case "value":
									this.peakValue = this.peakWidthParameters[properties][parameter];
									break;
								case "asymmetryConditionParameter":
									this.peakAsymmetryCondition = this.peakWidthParameters[properties][parameter];
									break;
								case "asymmetryValueParameter":
									this.peakAsymmetryValue = this.peakWidthParameters[properties][parameter];
									break;
								}
							}
						}
						if (flagPeakWidthChecked) {
							flagPeakWidth = true;
							auxResult = this.peakWidthFilterParametersValidation();
							if (auxResult.status === SpectrumQuality_Engine.status.PASSED) {
								auxResult = this.processPeakWidth(spectrum, this.peakType, this.peakHeightAt, this.peakCondition, this.peakValue, this.peakWidthDecimals, this.peakWidthFullSpectrum, this.peakFrom, this.peakTo, this.peakAsymmetryCondition, this.peakAsymmetryValue, document);
								flagPeakPicking = true;
								switch (auxResult.status) {
								case SpectrumQuality_Engine.status.FAILED:
									result.status = SpectrumQuality_Engine.status.FAILED;
									result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.PERFORMED;
									flagTestPerformed = true;
									if (peakWidthTotalParameters === 1) {
										auxStringResult = "\n[WARNING]: Peak Width test:";
									} else {
										auxStringResult = "\n[WARNING]: Peak Width test #" + i + ":";
									}
									if (this.peakValue !== undefined && !isNaN(this.peakValue) && this.peakCondition !== undefined && this.peakCondition !== "") {
										auxStringResult += " FAILED";
										flagTestFailedOrPassed = true;
										result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.FAILED;
									} else {
										auxStringResult += " PERFORMED";
									}
									auxLog += auxStringResult + auxResult.log;
									break;
								case SpectrumQuality_Engine.status.PASSED:
									result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.PERFORMED;
									flagTestPerformed = true;
									if (peakWidthTotalParameters === 1) {
										auxStringResult = "\n[INFO]: Peak Width test:";
									} else {
										auxStringResult = "\n[INFO]: Peak Width test #" + i + ":";
									}
									if (this.peakValue !== undefined && !isNaN(this.peakValue) && this.peakCondition !== undefined && this.peakCondition !== "") {
										auxStringResult += " PASSED";
										flagTestFailedOrPassed = true;
										result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.PASSED;
									} else {
										auxStringResult += " PERFORMED";
									}
									auxLog += auxStringResult;
									if (this.debugMode !== undefined && this.debugMode) {
										auxLog += auxResult.log;
									}
									break;
								case SpectrumQuality_Engine.status.UNTESTED:
									if (peakWidthTotalParameters === 1) {
										if (this.peakValue !== undefined && !isNaN(this.peakValue) && this.peakCondition !== undefined && this.peakCondition !== "") {
											auxStringResult = "\n[WARNING]: Peak Width test: UNTESTED";
											result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.UNTESTED;
										} else {
											auxStringResult = "\n[WARNING]: Peak Width test: NOT PERFORMED";
											result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.NOT_PERFORMED;
										}
									} else {
										if (this.peakValue !== undefined && !isNaN(this.peakValue) && this.peakCondition !== undefined && this.peakCondition !== "") {
											auxStringResult = "\n[WARNING]: Peak Width test #" + i + ": UNTESTED";
											result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.UNTESTED;
										} else {
											auxStringResult = "\n[WARNING]: Peak Width test #" + i + ": NOT PERFORMED";
											result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.NOT_PERFORMED;
										}
									}
									auxLog += auxStringResult + auxResult.log;
									break;
								}
							} else {
								result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.NOT_PERFORMED;
								if (peakWidthTotalParameters === 1) {
									auxStringResult = "\n[ERROR]: Peak Width test";
								} else {
									auxStringResult = "\n[ERROR]: Peak Width test #" + i + ":";
								}
								if (this.peakValue !== undefined) {
									auxStringResult += " UNTESTED";
									result.status = SpectrumQuality_Engine.status.UNTESTED;
									result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.UNTESTED;
								}
								auxLog += auxStringResult + auxResult.log;
							}
							result.peakWidthTest[peakWidthTest].desc = auxStringResult + auxResult.log;
						} else {
							result.peakWidthTest[peakWidthTest].status = SpectrumQuality_Engine.status.NOT_USED;
							result.peakWidthTest[peakWidthTest].desc = "\n[INFO]: The peak width test #" + i + " has not been enabled";
						}
						if (result.peakWidthTest[peakWidthTest].status === SpectrumQuality_Engine.status.UNTESTED) {
							flagPeakWidthUntested = true;
						}
					}
				}
			}
		} else {
			flagPeakWidth = false;
		}

		//Check quality regarding the peak intensity test
		result.peakIntensityTest = {};
		flagIntensityUntested = false;
		if (this.peakIntensityFilterStatus !== undefined && this.peakIntensityFilterStatus) {
			if (this.clearPeaksBeforStartingEachProcess !== undefined && this.clearPeaksBeforStartingEachProcess) {
				spectrum.peaks().clear();
				spectrum.multiplets().clear();
			}
			i = 0;
			intensityTotalParameters = this.getNumberOfIntensityTests(this.peakIntensityParameters, "checked");
			for (properties in this.peakIntensityParameters) {
				if (this.peakIntensityParameters.hasOwnProperty(properties)) {
					i++;
					intensityTest = "test" + i;
					result.peakIntensityTest[intensityTest] = {};
					if (!isNaN(properties)) {
						flagIntensityChecked = false;
						for (parameter in this.peakIntensityParameters[properties]) {
							if (this.peakIntensityParameters[properties].hasOwnProperty(parameter)) {
								if (parameter === "checked" && this.peakIntensityParameters[properties][parameter]) {
									flagIntensityChecked = true;
								}
								switch (parameter) {
								case "fromPPM":
									this.peakIntensityFrom = this.peakIntensityParameters[properties][parameter];
									break;
								case "toPPM":
									this.peakIntensityTo = this.peakIntensityParameters[properties][parameter];
									break;
								case "peakType":
									this.peakType = this.peakIntensityParameters[properties][parameter];
									break;
								case "condition":
									this.peakIntensityCondition = this.peakIntensityParameters[properties][parameter];
									break;
								case "value":
									this.peakIntensityValue = this.peakIntensityParameters[properties][parameter];
									break;
								}
							}
						}
						if (flagIntensityChecked) {
							flagIntensity = true;
							auxResult = this.peakIntensityFilterParametersValidation();
							if (auxResult.status === SpectrumQuality_Engine.status.PASSED) {
								auxResult = this.processIntensity(spectrum, this.peakType, this.peakIntensityCondition, this.peakIntensityValue, this.peakIntensityDecimals, this.peakIntensityFullSpectrum, this.peakIntensityFrom, this.peakIntensityTo, document);
								flagPeakPicking = true;
								switch (auxResult.status) {
								case SpectrumQuality_Engine.status.FAILED:
									result.status = SpectrumQuality_Engine.status.FAILED;
									result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.PERFORMED;
									flagTestPerformed = true;
									if (intensityTotalParameters === 1) {
										auxStringResult = "\n[WARNING]: Peak Intensity test:";
									} else {
										auxStringResult = "\n[WARNING]: Peak Intensity test #" + i + ":";
									}
									if (this.peakIntensityValue !== undefined && !isNaN(this.peakIntensityValue) && this.peakIntensityCondition !== undefined && this.peakIntensityCondition !== "") {
										auxStringResult += " FAILED";
										flagTestFailedOrPassed = true;
										result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.FAILED;
									} else {
										auxStringResult += " PERFORMED";
									}
									auxLog += auxStringResult + auxResult.log;
									break;
								case SpectrumQuality_Engine.status.PASSED:
									result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.PERFORMED;
									flagTestPerformed = true;
									if (intensityTotalParameters === 1) {
										auxStringResult = "\n[INFO]: Peak Intensity test:";
									} else {
										auxStringResult = "\n[INFO]: Peak Intensity test #" + i + ":";
									}
									if (this.peakIntensityValue !== undefined && !isNaN(this.peakIntensityValue) && this.peakIntensityCondition !== undefined && this.peakIntensityCondition !== "") {
										auxStringResult += " PASSED";
										flagTestFailedOrPassed = true;
										result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.PASSED;
									} else {
										auxStringResult += " PERFORMED";
									}
									auxLog += auxStringResult;
									if (this.debugMode !== undefined && this.debugMode) {
										auxLog += auxResult.log;
									}
									break;
								case SpectrumQuality_Engine.status.UNTESTED:
									if (intensityTotalParameters === 1) {
										if (this.peakIntensityValue !== undefined && !isNaN(this.peakIntensityValue) && this.peakIntensityCondition !== undefined && this.peakIntensityCondition !== "") {
											auxStringResult = "\n[WARNING]: Peak Intensity test: UNTESTED";
											result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.UNTESTED;
										} else {
											auxStringResult = "\n[WARNING]: Peak Intensity test: NOT PERFORMED";
											result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.NOT_PERFORMED;
										}
									} else {
										if (this.peakIntensityValue !== undefined && !isNaN(this.peakIntensityValue) && this.peakIntensityCondition !== undefined && this.peakIntensityCondition !== "") {
											auxStringResult = "\n[WARNING]: Peak Intensity test #" + i + ": UNTESTED";
											result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.UNTESTED;
										} else {
											auxStringResult = "\n[WARNING]: Peak Intensity test #" + i + ": NOT PERFORMED";
											result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.NOT_PERFORMED;
										}
									}
									auxLog += auxStringResult + auxResult.log;
									break;
								}
							} else {
								result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.NOT_PERFORMED;
								if (intensityTotalParameters === 1) {
									auxStringResult = "\n[ERROR]: Peak Intensity test";
								} else {
									auxStringResult = "\n[ERROR]: Peak Intensity test #" + i + ":";
								}
								if (this.peakIntensityValue !== undefined) {
									auxStringResult += " UNTESTED";
									result.status = SpectrumQuality_Engine.status.UNTESTED;
									result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.UNTESTED;
								}
								auxLog += auxStringResult + auxResult.log;
							}
							result.peakIntensityTest[intensityTest].desc = auxStringResult + auxResult.log;
						} else {
							result.peakIntensityTest[intensityTest].status = SpectrumQuality_Engine.status.NOT_USED;
							result.peakIntensityTest[intensityTest].desc = "\n[INFO]: The peak intensity test #" + i + " has not been enabled";
						}
						if (result.peakIntensityTest[intensityTest].status === SpectrumQuality_Engine.status.UNTESTED) {
							flagIntensityUntested = true;
						}
					}
				}
			}
		} else {
			flagIntensity = false;
		}

		//Check quality regarding the purity test
		result.purityTest = {};
		if (this.purityFilterStatus !== undefined && this.purityFilterStatus) {
			auxResult = this.purityParametersValidation();
			if (auxResult.status === SpectrumQuality_Engine.status.PASSED) {
				auxResult = this.processPurity(spectrum, document, this.purityCondition, this.purityValue);
				flagPeakPicking = true;
			} else {
				auxResult2 = this.processPurity(spectrum, document);
				flagPeakPicking = true;
				if (auxResult2.status !== SpectrumQuality_Engine.status.PASSED) {
					auxResult = auxResult2;
				}
				auxResult.log += auxResult2.log;
			}
			switch (auxResult.status) {
			case SpectrumQuality_Engine.status.FAILED:
				result.status = SpectrumQuality_Engine.status.FAILED;
				result.purityTest.status = SpectrumQuality_Engine.status.PERFORMED;
				flagTestPerformed = true;
				auxStringResult = "\n[WARNING]: Purity test:";
				if (this.purityCondition !== undefined && this.purityValue !== undefined && this.purityCondition !== "") {
					auxStringResult += " FAILED";
					flagTestFailedOrPassed = true;
					result.purityTest.status = SpectrumQuality_Engine.status.FAILED;
				} else {
					auxStringResult += " PERFORMED";
				}
				auxLog += auxStringResult + auxResult.log;
				break;
			case SpectrumQuality_Engine.status.PASSED:
				result.purityTest.status = SpectrumQuality_Engine.status.PERFORMED;
				flagTestPerformed = true;
				auxStringResult = "\n[INFO]: Purity test:";
				if (this.purityCondition !== undefined && this.purityValue !== undefined && this.purityCondition !== "") {
					auxStringResult += " PASSED";
					flagTestFailedOrPassed = true;
					result.purityTest.status = SpectrumQuality_Engine.status.PASSED;
				} else {
					auxStringResult += " PERFORMED";
				}
				auxLog += auxStringResult;
				if (this.debugMode !== undefined && this.debugMode) {
					auxLog += auxResult.log;
				}
				break;
			case SpectrumQuality_Engine.status.UNTESTED:
				if (this.purityCondition !== undefined && this.purityValue !== undefined && this.purityCondition !== "") {
					auxStringResult = "\n[WARNING]: Purity test: UNTESTED";
					result.purityTest.status = SpectrumQuality_Engine.status.UNTESTED;
				} else {
					auxStringResult = "\n[WARNING]: Purity test: NOT PERFORMED";
					result.purityTest.status = SpectrumQuality_Engine.status.NOT_PERFORMED;
				}
				auxLog += auxStringResult + auxResult.log;
				break;
			}
			result.purityTest.desc = auxStringResult + auxResult.log;
		} else {
			result.purityTest.status = SpectrumQuality_Engine.status.NOT_USED;
			result.purityTest.desc = "\n[INFO]: The purity test has not been enabled";
		}

		//Check quality regarding the digital resolution test
		result.digitalResolutionTest = {};
		if (this.digitalResolutionFilterStatus !== undefined && this.digitalResolutionFilterStatus) {
			auxResult = this.digitalResolutionParametersValidation();
			if (auxResult.status === SpectrumQuality_Engine.status.PASSED) {
				auxResult = this.processDigitalResolution(spectrum, this.digitalResolutionCondition, this.digitalResolutionValue);
			} else {
				auxResult2 = this.processDigitalResolution(spectrum, document);
				if (auxResult2.status !== SpectrumQuality_Engine.status.PASSED) {
					auxResult = auxResult2;
				}
				auxResult.log += auxResult2.log;
			}
			switch (auxResult.status) {
			case SpectrumQuality_Engine.status.FAILED:
				result.status = SpectrumQuality_Engine.status.FAILED;
				result.digitalResolutionTest.status = SpectrumQuality_Engine.status.PERFORMED;
				flagTestPerformed = true;
				auxStringResult = "\n[WARNING]: Digital Resolution test:";
				if (this.digitalResolutionCondition !== undefined && this.digitalResolutionValue !== undefined && this.digitalResolutionCondition !== "") {
					auxStringResult += " FAILED";
					flagTestFailedOrPassed = true;
					result.digitalResolutionTest.status = SpectrumQuality_Engine.status.FAILED;
				} else {
					auxStringResult += " PERFORMED";
				}
				auxLog += auxStringResult + auxResult.log;
				break;
			case SpectrumQuality_Engine.status.PASSED:
				result.digitalResolutionTest.status = SpectrumQuality_Engine.status.PERFORMED;
				flagTestPerformed = true;
				auxStringResult = "\n[INFO]: Digital Resolution test:";
				if (this.digitalResolutionCondition !== undefined && this.digitalResolutionValue !== undefined && this.digitalResolutionCondition !== "") {
					auxStringResult += " PASSED";
					flagTestFailedOrPassed = true;
					result.digitalResolutionTest.status = SpectrumQuality_Engine.status.PASSED;
				} else {
					auxStringResult += " PERFORMED";
				}
				auxLog += auxStringResult;
				if (this.debugMode !== undefined && this.debugMode) {
					auxLog += auxResult.log;
				}
				break;
			case SpectrumQuality_Engine.status.UNTESTED:
				if (this.digitalResolutionCondition !== undefined && this.digitalResolutionValue !== undefined && this.digitalResolutionCondition !== "") {
					auxStringResult = "\n[WARNING]: Digital Resolution test: UNTESTED";
					result.digitalResolutionTest.status = SpectrumQuality_Engine.status.UNTESTED;
				} else {
					auxStringResult = "\n[WARNING]: Digital Resolution test: NOT PERFORMED";
					result.digitalResolutionTest.status = SpectrumQuality_Engine.status.NOT_PERFORMED;
				}
				auxLog += auxStringResult + auxResult.log;
				break;
			}
			result.digitalResolutionTest.desc = auxStringResult + auxResult.log;
		} else {
			result.digitalResolutionTest.status = SpectrumQuality_Engine.status.NOT_USED;
			result.digitalResolutionTest.desc = "\n[INFO]: The digital resolution test has not been enabled";
		}

		//--------------------------Header Log Management--------------------------
		//Management of the header log according to the general options used. This information will be shown at the header

		//"Keep Current Data" option log management
		if (aParameters !== undefined && aParameters.keepCurrentData !== undefined) {
			optionNameInViewerEnabled = ": " + SpectrumQuality_Viewer.generalOptions.KeepCurrentData + " is checked";
			optionNameInViewerDisabled = ": " + SpectrumQuality_Viewer.generalOptions.KeepCurrentData + " is not checked";
		} else {
			optionNameInViewerEnabled = "";
			optionNameInViewerDisabled = "";
		}
		if (this.performSQAUsingSpectrumCopyInHiddenDocument !== undefined && this.performSQAUsingSpectrumCopyInHiddenDocument) {
			if (flagCloneHiddenSpectrum) {
				result.log += "\n[INFO]" + optionNameInViewerEnabled + ": Analysis performed using a copy of the document " + spectrum.title + " in the background";
			} else {
				result.log += "\n[WARNING]" + optionNameInViewerEnabled + ": Unable to clone spectrum " + spectrum.title + " to a background document. The original one will be used the original instead. Some manual changes may be overwritten";
			}
			if (flagHiddenDocument) {
				if (hiddenDocument !== undefined) {
					if (hiddenDocument.uuid !== undefined && hiddenDocument.uuid !== "") {
						hiddenDocument.destroy();
						if (hiddenDocument === undefined || hiddenDocument.uuid === undefined || hiddenDocument.uuid === "") {
							result.log += "\n[INFO]" + optionNameInViewerEnabled + ": The background document has been successfully removed at the end";
						} else {
							result.log += "\n[WARNING]" + optionNameInViewerEnabled + ": Unable to remove the background document at the end";
						}
					}
				}
			}
		} else {
			result.log += "\n[INFO]" + optionNameInViewerDisabled + ": Analysis performed using the original spectrum";
		}

		//"Use Current Analysis" option log management
		if (aParameters !== undefined && aParameters.useCurrentAnalysis !== undefined) {
			optionNameInViewerEnabled = ": " + SpectrumQuality_Viewer.generalOptions.UseCurrentAnalysis + " is checked";
			optionNameInViewerDisabled = ": " + SpectrumQuality_Viewer.generalOptions.UseCurrentAnalysis + " is not checked";
		} else {
			optionNameInViewerEnabled = "";
			optionNameInViewerDisabled = "";
		}
		if (this.clearPeaksBeforStartingEachProcess !== undefined && !this.clearPeaksBeforStartingEachProcess && this.deletePreviousPeaksAtSNR !== undefined && !this.deletePreviousPeaksAtSNR) {
			if (flagUseCurrentAnalysis && !flagPreviousPeaks && flagPeakPicking) {
				result.log += "\n[WARNING]" + optionNameInViewerEnabled + ": No peaks are present. A peak picking applying SQA default settings is performed to complete the SQA analyses";
			} else {
				result.log += "\n[INFO]" + optionNameInViewerEnabled + ": The current analysis has been used. No specific analysis of SQA has been performed";
			}
		} else {
			result.log += "\n[INFO]" + optionNameInViewerDisabled + ": The specific analysis of SQA has been performed";
		}

		//End of header section. Below this line the information will be related to SQA tests
		result.log += "\n[INFO]: Quality test spectrum for " + spectrumTitle + ":";

		//Final result information management (summary)
		//This information will be shown at the beginning
		if (flagTestFailedOrPassed === undefined && flagTestPerformed === undefined) {
			if ((result.acquisitionParametersTest.status === SpectrumQuality_Engine.status.NOT_USED) && (result.processingParametersTest.status === SpectrumQuality_Engine.status.NOT_USED) && (result.signalToNoiseTest.status === SpectrumQuality_Engine.status.NOT_USED) && (result.phaseErrorTest.status === SpectrumQuality_Engine.status.NOT_USED) && (!flagPeakWidth) && (!flagIntensity) && (result.purityTest.status === SpectrumQuality_Engine.status.NOT_USED) && (result.digitalResolutionTest.status === SpectrumQuality_Engine.status.NOT_USED)) {
				result.log += "\n[WARNING]: All test have been DISABLED";
				result.status = SpectrumQuality_Engine.status.NOT_USED;
			} else {
				if ((result.acquisitionParametersTest.status === SpectrumQuality_Engine.status.UNTESTED) || (result.processingParametersTest.status === SpectrumQuality_Engine.status.UNTESTED) || (result.signalToNoiseTest.status === SpectrumQuality_Engine.status.UNTESTED) || (result.phaseErrorTest.status === SpectrumQuality_Engine.status.UNTESTED) || (flagPeakWidthUntested) || (flagIntensity) || (result.purityTest.status === SpectrumQuality_Engine.status.UNTESTED) || (result.digitalResolutionTest.status === SpectrumQuality_Engine.status.UNTESTED)) {
					result.log += "\n[WARNING]: One or more tests have been UNTESTED";
					result.status = SpectrumQuality_Engine.status.UNTESTED;
				} else {
					result.log += "\n[WARNING]: It has NOT been found a test to PERFORM";
					result.status = SpectrumQuality_Engine.status.NOT_PERFORMED;
				}
			}
		} else if (flagTestFailedOrPassed) {
			if (result.status === SpectrumQuality_Engine.status.PASSED) {
				result.log += "\n[INFO]: All tests have been PASSED";
			} else {
				result.log += "\n[WARNING]: The spectrum has FAILED one or more tests";
			}
		} else if (flagTestPerformed !== undefined) {
			result.log += "\n[INFO]: The spectrum has PERFORMED one or more tests";
			result.status = SpectrumQuality_Engine.status.PERFORMED;
		}

		//Then we show the detailed information for each test
		if (auxLog !== "") {
			result.log += auxLog;
			auxLog = "";
		}

		//Restore feature only make sense with the original spectrum.
		//Restore zoom, view and several options
		if (flagOriginalSpectrum) {
			spectrum.zoom(auxZoom);
			spectrum.setProperty("peaks.show", auxView);
			if (!flagPreviousPeaks) {
				spectrum.peaks().clear();
			}
			if (!flagPreviousMultiplets) {
				spectrum.multiplets().clear();
			}

			//Restore previous Peak Picking values
			if (flagPeakPicking) {
				if (spectrum.proc !== undefined) {
					if (currentPeakPickingState !== undefined && currentPeakPickingState !== "") {
						processingTemplate.setParameter("PP.Apply", currentPeakPickingState);
					}
					if (currentPeakPickingMethod !== undefined && currentPeakPickingMethod !== "") {
						processingTemplate.setParameter("PP.Method", currentPeakPickingMethod);
						if (currentPeakPickingMethod === "GSD") {
							if (currentPeakPickingqQSD !== undefined && currentPeakPickingqQSD !== "") {
								processingTemplate.setParameter("PP.GSD.qGSDApply", currentPeakPickingqQSD);
							}
						}
					}
					if (currentPeakPickingAutoClassify !== undefined && currentPeakPickingAutoClassify !== "") {
						processingTemplate.setParameter("PP.AutoClassify", currentPeakPickingAutoClassify);
					}
				}
			}

			//Update all
			spectrum.update();
			document.update();
			mainWindow.processEvents();
		}

		return result;
	};
}


//------------------------------STATIC ATTRIBUTES-------------------------------------
SpectrumQuality_Engine.status = {
	FAILED: 0,
	PASSED: 1,
	PERFORMED: 2,
	UNTESTED: 3,
	NOT_PERFORMED: 4,
	NOT_USED: 5
};
SpectrumQuality_Engine.userCondition = {
	EQ: "=",
	NE: "≠",
	LT: "<",
	LE: "≤",
	GT: ">",
	GE: "≥"
};
SpectrumQuality_Engine.programmingCondition = {
	EQ: "===",
	NE: "!==",
	LT: "<",
	LE: "<=",
	GT: ">",
	GE: ">="
};
SpectrumQuality_Engine.phaseErrorCondition = SpectrumQuality_Engine.userCondition.LT;
SpectrumQuality_Engine.purityCondition = SpectrumQuality_Engine.userCondition.GE;
SpectrumQuality_Engine.digitalResolutionCondition = SpectrumQuality_Engine.userCondition.LE;


//------------------------------STATIC METHODS-------------------------------------
SpectrumQuality_Engine.getUniqueArray = function (array, aIsObject) {
	"use strict";

	return array.filter(function (item, index, array) {
		var result, i;

		result = -1;
		for (i = 0; i < array.length; i++) {
			if (aIsObject === undefined || aIsObject) {
				if (array[i].row === item.row) {
					result = i;
				}
			} else {
				if (array[i] === item) {
					result = i;
				}
			}
		}
		return index === result;
	});
};

SpectrumQuality_Engine.getDefaultTemplates = function (aConfigurationObject, aDimension) {
	"use strict";

	var dataTemplates, currentTemplate;

	dataTemplates = aConfigurationObject.getDataTemplates(aDimension);
	currentTemplate = aConfigurationObject.getDefaultTemplateIndex(aDimension);

	return [dataTemplates, currentTemplate];
};

SpectrumQuality_Engine.getProcessingReportTemplates = function (aDimCount) {
	"use strict";

	var current1DTemplateKey, current2DTemplateKey, currentDataTemplatesKey, dataTemplates, currentTemplate,
		flagErrorsSettings, processingParametersReporter_Configuration, resultDefaultTemplates, templateFile;

	//Registry Entries to take information since configuration script
	current1DTemplateKey = "Processing Parameters Report/Current 1D Template";
	current2DTemplateKey = "Processing Parameters Report/Current 2D Template";
	currentDataTemplatesKey = "Processing Parameters Report/Data Templates";

	//Load registry information
	if (aDimCount === 1) {
		currentTemplate = settings.value(current1DTemplateKey, -1);
	} else if (aDimCount === 2) {
		currentTemplate = settings.value(current2DTemplateKey, -1);
	}
	dataTemplates = settings.value(currentDataTemplatesKey, "");
	if (dataTemplates !== "") {
		dataTemplates = JSON.parse(dataTemplates);
	}

	flagErrorsSettings = false;
	processingParametersReporter_Configuration = new ProcessingParametersReporter_Configuration();
	resultDefaultTemplates = [];

	//Manage possible problems by getting default templates
	if (aDimCount === 1 && (dataTemplates.length === undefined || dataTemplates.length < 1 || currentTemplate === -1)) {
		resultDefaultTemplates = SpectrumQuality_Engine.getDefaultTemplates(processingParametersReporter_Configuration, 1);
		flagErrorsSettings = true;
	}
	if (aDimCount === 2 && (dataTemplates.length === undefined || dataTemplates.length < 1 || currentTemplate === -1)) {
		resultDefaultTemplates = SpectrumQuality_Engine.getDefaultTemplates(processingParametersReporter_Configuration, 2);
		flagErrorsSettings = true;
	}

	//Check for the integration files
	if (!flagErrorsSettings && dataTemplates.length > 0) {
		processingParametersReporter_Configuration.setDataTemplates(dataTemplates);
		dataTemplates = processingParametersReporter_Configuration.filterTemplateByDimension(aDimCount);
		if (!(new File(dataTemplates[currentTemplate].path).exists)) {
			resultDefaultTemplates = SpectrumQuality_Engine.getDefaultTemplates(processingParametersReporter_Configuration, aDimCount);
			flagErrorsSettings = true;
		}
	}

	//Mapping the vars to the currents ones
	if (flagErrorsSettings) {
		dataTemplates = resultDefaultTemplates[0];
		currentTemplate = resultDefaultTemplates[1];
	}

	//Choose the proper template file by using the dimension parameter
	templateFile = dataTemplates[currentTemplate].path;

	return templateFile;
};

SpectrumQuality_Engine.getIndexStringOccurrences = function (aSearchString, aWholeString, aCaseSensitive) {
	"use strict";

	var startIndex, searchStrLen, index, arrayIndexes;

	startIndex = 0;
	searchStrLen = aSearchString.length;
	arrayIndexes = [];

	if (!aCaseSensitive) {
		aWholeString = aWholeString.toLowerCase();
		aSearchString = aSearchString.toLowerCase();
	}

	while ((index = aWholeString.indexOf(aSearchString, startIndex)) > -1) {
		arrayIndexes.push(index);
		startIndex = index + searchStrLen;
	}

	if (arrayIndexes.length === 0) {
		arrayIndexes.push("-1");
	}

	return arrayIndexes;
};

SpectrumQuality_Engine.depureProcessingParameterValues = function (aValue) {
	"use strict";

	var i, startIndexes, startIndex, lastIndex, value, result;

	result = [];
	startIndexes = SpectrumQuality_Engine.getIndexStringOccurrences("getParameter('", aValue, false);
	if (startIndexes.length === 1 && startIndexes[0] === "-1") {
		result.push(aValue);
	} else {
		for (i = 0; i < startIndexes.length; i++) {
			startIndex = startIndexes[i] + "getParameter('".length;
			lastIndex = aValue.indexOf("')", startIndex);
			value = aValue.substring(startIndex, lastIndex);
			result.push(value);
		}
	}

	return result;
};

SpectrumQuality_Engine.getProcessingParameters = function (aTemplateFile) {
	"use strict";

	var i, j, template, processingParameters, value, values;

	processingParameters = [];
	template = new Template(aTemplateFile);
	if (template.getTemplateItems()) {
		//Process each template item row
		for (i = 0; i < template.maxRowsFieldItems; i++) {
			value = template.fieldItems[i][2];
			if (value !== "") {
				values = SpectrumQuality_Engine.depureProcessingParameterValues(value);
				for (j = 0; j < values.length; j++) {
					processingParameters.push(values[j]);
				}
			}
		}
	}

	return processingParameters;
};

/****************************VIEWER CLASS********************************
************************************************************************/
function SpectrumQuality_Viewer(aGetInstanceAttributes, aSettingsMode) {
	'use strict';

	var i, generalDataFile, engine, results, flagFirstTime,
		htmlReport, dialogAnswer, processingParameters,
		flagShowGuiIfErrors, flagExit, generalSettingsDialog;

	//Instance Attributes. Check row counter to manage buttons properly
	this.acquisitionParameter = {};
	this.acquisitionParameter.totalRowsChecked = 0;
	this.acquisitionParameter.checkBoxParameter = 0;
	this.acquisitionParameter.numericConstraintForCheckBoxParameter = false;
	this.acquisitionParameter.parameterParameter = 1;
	this.acquisitionParameter.numericConstraintForParameterParameter = false;
	this.acquisitionParameter.conditionParameter = 2;
	this.acquisitionParameter.numericConstraintForConditionParameter = false;
	this.acquisitionParameter.valueParameter = 3;
	this.acquisitionParameter.numericConstraintForValueParameter = false;
	this.acquisitionParameter.defaultTextInTableWidget = "";
	this.acquisitionParameter.defaultAlignmentInTableWidget = 132;
	this.acquisitionParameter.defaultFlagsInTableWidget = 35;

	this.processingParameter = {};
	this.processingParameter.totalRowsChecked = 0;
	this.processingParameter.checkBoxParameter = 0;
	this.processingParameter.numericConstraintForCheckBoxParameter = false;
	this.processingParameter.parameterParameter = 1;
	this.processingParameter.numericConstraintForParameterParameter = false;
	this.processingParameter.conditionParameter = 2;
	this.processingParameter.numericConstraintForConditionParameter = false;
	this.processingParameter.valueParameter = 3;
	this.processingParameter.numericConstraintForValueParameter = false;
	this.processingParameter.defaultTextInTableWidget = "";
	this.processingParameter.defaultAlignmentInTableWidget = 132;
	this.processingParameter.defaultFlagsInTableWidget = 35;

	this.peakWidth = {};
	this.peakWidth.totalRowsChecked = 0;
	this.peakWidth.checkBoxParameter = 0;
	this.peakWidth.numericConstraintForCheckBoxParameter = false;
	this.peakWidth.fromPPM = 1;
	this.peakWidth.numericConstraintForFromPPM = true;
	this.peakWidth.toPPM = 2;
	this.peakWidth.numericConstraintForToPPM = true;
	this.peakWidth.peakType = 3;
	this.peakWidth.numericConstraintForPeakType = false;
	this.peakWidth.atHeight = 4;
	this.peakWidth.numericConstraintForAtHeight = true;
	this.peakWidth.conditionParameter = 5;
	this.peakWidth.numericConstraintForConditionParameter = false;
	this.peakWidth.valueParameter = 6;
	this.peakWidth.numericConstraintForValueParameter = true;
	this.peakWidth.asymmetryConditionParameter = 7;
	this.peakWidth.numericConstraintForAsymmetryConditionParameter = false;
	this.peakWidth.asymmetryValueParameter = 8;
	this.peakWidth.numericConstraintForAsymmetryValueParameter = true;
	this.peakWidth.defaultTextInTableWidget = "";
	this.peakWidth.defaultAlignmentInTableWidget = 132;
	this.peakWidth.defaultFlagsInTableWidget = 35;

	this.peakIntensity = {};
	this.peakIntensity.totalRowsChecked = 0;
	this.peakIntensity.checkBoxParameter = 0;
	this.peakIntensity.numericConstraintForCheckBoxParameter = false;
	this.peakIntensity.fromPPM = 1;
	this.peakIntensity.numericConstraintForFromPPM = true;
	this.peakIntensity.toPPM = 2;
	this.peakIntensity.numericConstraintForToPPM = true;
	this.peakIntensity.peakType = 3;
	this.peakIntensity.numericConstraintForPeakType = false;
	this.peakIntensity.conditionParameter = 4;
	this.peakIntensity.numericConstraintForConditionParameter = false;
	this.peakIntensity.valueParameter = 5;
	this.peakIntensity.numericConstraintForValueParameter = true;
	this.peakIntensity.defaultTextInTableWidget = "";
	this.peakIntensity.defaultAlignmentInTableWidget = 132;
	this.peakIntensity.defaultFlagsInTableWidget = 35;

	this.numericContraintForValueParameterInParametersTable = false;

	this.acquisitionParametersKey = "Spectrum Quality/Acquisition Parameters";
	this.acquisitionParametersGUIKey = "Spectrum Quality/Acquisition Parameters GUI Table";
	this.processingParametersKey = "Spectrum Quality/Processing Parameters";
	this.processingParametersGUIKey = "Spectrum Quality/Processing Parameters GUI Table";
	this.signalToNoiseStatusKey = "Spectrum Quality/Signal-to-Noise Status";
	this.signalFullSpectrumKey = "Spectrum Quality/Signal Full Spectrum";
	this.signalFromKey = "Spectrum Quality/Signal From PPM";
	this.signalToKey = "Spectrum Quality/Signal To PPM";
	this.noiseAutomaticKey = "Spectrum Quality/Automatic Noise";
	this.noiseFromKey = "Spectrum Quality/Noise From PPM";
	this.noiseToKey = "Spectrum Quality/Noise To PPM";
	this.snrMinValueKey = "Spectrum Quality/SNR Minimum Value";
	this.phaseStatusKey = "Spectrum Quality/Phase Status";
	this.phaseConditionKey = "Spectrum Quality/Phase Condition";
	this.phaseValueKey = "Spectrum Quality/Phase Value";
	this.peakStatusKey = "Spectrum Quality/Peak Width Status";
	this.peakWidthKey = "Spectrum Quality/Peak Width";
	this.peakWidthGUIKey = "Spectrum Quality/Peak Width GUI Table";
	this.peakIntensityStatusKey = "Spectrum Quality/Peak Intensity Status";
	this.peakIntensityKey = "Spectrum Quality/Peak Intensity";
	this.peakIntensityGUIKey = "Spectrum Quality/Peak Intensity GUI Table";
	this.purityStatusKey = "Spectrum Quality/Purity Status";
	this.purityConditionKey = "Spectrum Quality/Purity Condition";
	this.purityValueKey = "Spectrum Quality/Purity Value";
	this.digitalResolutionStatusKey = "Spectrum Quality/Digital Resolution Status";
	this.digitalResolutionConditionKey = "Spectrum Quality/Digital Resolution Condition";
	this.digitalResolutionValueKey = "Spectrum Quality/Digital Resolution Value";

	//It only returns the above instance attributes
	if (aGetInstanceAttributes !== undefined && !aGetInstanceAttributes) {
		flagExit = true;
	} else {

		flagExit = false;

		//Load UI into the dialog instance attribute
		//It changes the name of the dialog depending on the execution mode
		this.dialog = {};
		this.dialog = Application.loadUiFile('ricares:SpectrumQuality.ui');
		if (aSettingsMode !== undefined && aSettingsMode === true) {
			this.dialog.title = this.dialog.title + " Settings";
		}

		//Do not show the dialog if the aSettingsMode is defined as true
		//The aim of this parameter is to show the dialog only if we have a valid dataset to be processed
		//So The dialog will be shown later if necessary.
		if (aSettingsMode !== undefined && aSettingsMode === true) {
			this.dialog.show();
		}

		//Assign buttons and table widget to instance attributes
		this.acquisitionParameter.tableWidget = this.dialog.widgets.tableWidgetAcquisitionParameters;
		this.acquisitionParameter.tbAdd = this.dialog.widgets.tbAddAcquisitionParameters;
		this.acquisitionParameter.tbDelete = this.dialog.widgets.tbDeleteAcquisitionParameters;
		this.acquisitionParameter.tbCheckAll = this.dialog.widgets.tbCheckAllAcquisitionParameters;
		this.acquisitionParameter.tbUncheckAll = this.dialog.widgets.tbUncheckAllAcquisitionParameters;
		this.acquisitionParameter.addParametersTable = {};
		this.acquisitionParameter.addParametersTable.totalRowsChecked = 0;
		this.acquisitionParameter.addParametersTable.checkBoxParameter = 0;
		this.acquisitionParameter.addParametersTable.parameterParameter = 1;
		this.acquisitionParameter.addParametersTable.valueParameter = 2;
		this.acquisitionParameter.totalRowsLoaded = 0;
		this.acquisitionParameter.reflexion = "acquisitionParameter";

		this.processingParameter.tableWidget = this.dialog.widgets.tableWidgetProcessingParameters;
		this.processingParameter.tbAdd = this.dialog.widgets.tbAddProcessingParameters;
		this.processingParameter.tbDelete = this.dialog.widgets.tbDeleteProcessingParameters;
		this.processingParameter.tbCheckAll = this.dialog.widgets.tbCheckAllProcessingParameters;
		this.processingParameter.tbUncheckAll = this.dialog.widgets.tbUncheckAllProcessingParameters;
		this.processingParameter.addParametersTable = {};
		this.processingParameter.addParametersTable.totalRowsChecked = 0;
		this.processingParameter.addParametersTable.checkBoxParameter = 0;
		this.processingParameter.addParametersTable.parameterParameter = 1;
		this.processingParameter.addParametersTable.valueParameter = 2;
		this.processingParameter.totalRowsLoaded = 0;
		this.processingParameter.reflexion = "processingParameter";

		this.peakWidth.tableWidget = this.dialog.widgets.tableWidgetPeakWidth;
		this.peakWidth.tbAdd = this.dialog.widgets.tbAddPeakWidth;
		this.peakWidth.tbDelete = this.dialog.widgets.tbDeletePeakWidth;
		this.peakWidth.tbCheckAll = this.dialog.widgets.tbCheckAllPeakWidth;
		this.peakWidth.tbUncheckAll = this.dialog.widgets.tbUncheckAllPeakWidth;
		this.peakWidth.addParametersTable = {};
		this.peakWidth.addParametersTable.totalRowsChecked = 0;
		this.peakWidth.addParametersTable.checkBoxParameter = 0;
		this.peakWidth.addParametersTable.parameterParameter = 1;
		this.peakWidth.addParametersTable.valueParameter = 2;
		this.peakWidth.totalRowsLoaded = 0;
		this.peakWidth.reflexion = "peakWidth";

		this.peakIntensity.tableWidget = this.dialog.widgets.tableWidgetPeakIntensity;
		this.peakIntensity.tbAdd = this.dialog.widgets.tbAddPeakIntensity;
		this.peakIntensity.tbDelete = this.dialog.widgets.tbDeletePeakIntensity;
		this.peakIntensity.tbCheckAll = this.dialog.widgets.tbCheckAllPeakIntensity;
		this.peakIntensity.tbUncheckAll = this.dialog.widgets.tbUncheckAllPeakIntensity;
		this.peakIntensity.addParametersTable = {};
		this.peakIntensity.addParametersTable.totalRowsChecked = 0;
		this.peakIntensity.addParametersTable.checkBoxParameter = 0;
		this.peakIntensity.addParametersTable.parameterParameter = 1;
		this.peakIntensity.addParametersTable.valueParameter = 2;
		this.peakIntensity.totalRowsLoaded = 0;
		this.peakIntensity.reflexion = "intensity";

	}

	//------------------------------INSTANCE METHODS-------------------------------------
	SpectrumQuality_Viewer.prototype.clearTable = function (aTableWidget) {

		var i, auxLength;

		if (aTableWidget !== undefined) {
			auxLength = aTableWidget.items.length;
			aTableWidget.clearContents();
			for (i = 0; i < auxLength; i++) {
				aTableWidget.removeRow(0);
			}
		}
	};

	SpectrumQuality_Viewer.prototype.loadSettings = function () {

		var dataFile, file, stream, dataJSON, generalSettings, generalOptionsSettings, resultsViewerOptionsSettings;

		dataFile = FileDialog.getOpenFileName("*.data", "Open data", File.absDirPath(generalDataFile));
		if (dataFile !== "") {

			//Get data from file
			file = new File(dataFile);
			generalDataFile = file.name;
			file.open(File.ReadOnly);
			stream = new TextStream(file);
			stream.codec = "UTF-8";
			dataJSON = stream.readAll();
			generalSettings = JSON.parse(dataJSON);
			stream.flush();
			file.close();

			//Set data to the GUI components
			this.clearTable(this.dialog.widgets.tableWidgetAcquisitionParameters);
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetAcquisitionParameters, generalSettings.acquisitionParameters, this.acquisitionParameter.defaultTextInTableWidget, this.acquisitionParameter.defaultAlignmentInTableWidget, this.acquisitionParameter.defaultFlagsInTableWidget);
			this.clearTable(this.dialog.widgets.tableWidgetProcessingParameters);
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetProcessingParameters, generalSettings.processingParameters, this.processingParameter.defaultTextInTableWidget, this.processingParameter.defaultAlignmentInTableWidget, this.processingParameter.defaultFlagsInTableWidget);
			this.dialog.widgets.gbSignalToNoise.checked = generalSettings.signalToNoiseFilterStatus;
			this.dialog.widgets.leFromSignal.text = generalSettings.signalFrom;
			this.dialog.widgets.leToSignal.text = generalSettings.signalTo;
			this.dialog.widgets.leFromNoise.text = generalSettings.noiseFrom;
			this.dialog.widgets.leToNoise.text = generalSettings.noiseTo;
			this.dialog.widgets.leSignalNoiseMinimumValue.text = generalSettings.snrMinValue;
			this.dialog.widgets.gbPhase.checked = generalSettings.phaseFilterStatus;
			this.dialog.widgets.spbxPhaseValue.value = generalSettings.phaseValue;
			this.dialog.widgets.gbPeakWidth.checked = generalSettings.peakFilterStatus;
			this.clearTable(this.dialog.widgets.tableWidgetPeakWidth);
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetPeakWidth, generalSettings.peakWidth, this.peakWidth.defaultTextInTableWidget, this.peakWidth.defaultAlignmentInTableWidget, this.peakWidth.defaultFlagsInTableWidget);
			this.dialog.widgets.gbPeakIntensity.checked = generalSettings.peakIntensityFilterStatus;
			this.clearTable(this.dialog.widgets.tableWidgetPeakIntensity);
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetPeakIntensity, generalSettings.peakIntensity, this.peakIntensity.defaultTextInTableWidget, this.peakIntensity.defaultAlignmentInTableWidget, this.peakIntensity.defaultFlagsInTableWidget);
			this.dialog.widgets.gbPurity.checked = generalSettings.purityFilterStatus;
			this.dialog.widgets.spbxPurityValue.value = generalSettings.purityValue;
			this.dialog.widgets.gbDigitalResolution.checked = generalSettings.digitalResolutionFilterStatus;
			this.dialog.widgets.spbxDigitalResolutionValue.value = generalSettings.digitalResolutionValue;

			//Manage radio buttons
			if (generalSettings.signalFullSpectrum) {
				this.dialog.widgets.rbSignalFullSpectrum.checked = true;
			} else {
				this.dialog.widgets.rbRangeSignal.checked = true;
			}
			if (generalSettings.noiseAutomatic) {
				this.dialog.widgets.rbAutomaticNoise.checked = true;
			} else {
				this.dialog.widgets.rbRangeNoise.checked = true;
			}

			//Checking for incoherent values
			if (this.dialog.widgets.leFromSignal.text > this.dialog.widgets.leToSignal.text) {
				this.dialog.widgets.leToSignal.text = generalSettings.signalFrom;
				this.dialog.widgets.leFromSignal.text = generalSettings.signalTo;
			}
			if (this.dialog.widgets.leFromNoise.text > this.dialog.widgets.leToNoise.text) {
				this.dialog.widgets.leToNoise.text = generalSettings.noiseFrom;
				this.dialog.widgets.leFromNoise.text = generalSettings.noiseTo;
			}

			//Current tab index
			if (generalSettings.currentIndexTab !== undefined && !isNaN(generalSettings.currentIndexTab)) {
				this.dialog.widgets.tabWidget.currentIndex = generalSettings.currentIndexTab;
			}


			//Set data to general options GUI  - First Options Tab
			//Load general options dialog
			generalOptionsSettings = SpectrumQuality_Viewer.getGeneralOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityGeneralSettings.ui');

			//Append general options to the generalSettings object
			//Check for undefined objects in order to forwards compatibility be guaranteed
			if (generalSettings !== undefined) {
				if (generalSettings.generalOptions !== undefined) {
					if (generalOptionsSettings !== undefined) {
						if (generalOptionsSettings.widgets !== undefined) {
							if (generalSettings.generalOptions.currentIndexOptionTab !== undefined && !isNaN(generalSettings.generalOptions.currentIndexOptionTab)) {
								if (generalOptionsSettings.widgets.tabWidget !== undefined) {
									if (generalOptionsSettings.widgets.tabWidget.currentIndex !== undefined) {
										generalOptionsSettings.widgets.tabWidget.currentIndex = generalSettings.generalOptions.currentIndexOptionTab;
										settings.setValue(SpectrumQuality_Viewer.lastTabIndexViewedKey, generalSettings.generalOptions.currentIndexOptionTab);
									}
								}
							}
							if (generalSettings.generalOptions.keepCurrentData !== undefined) {
								if (generalOptionsSettings.widgets.cbKeepCurrentData !== undefined) {
									if (generalOptionsSettings.widgets.cbKeepCurrentData.checked !== undefined) {
										generalOptionsSettings.widgets.cbKeepCurrentData.checked = generalSettings.generalOptions.keepCurrentData;
										settings.setValue(SpectrumQuality_Viewer.keepCurrentDataKey, generalSettings.generalOptions.keepCurrentData);
									}
								}
							}
							if (generalSettings.generalOptions.useCurrentAnalysis !== undefined) {
								if (generalOptionsSettings.widgets.cbUseCurrentAnalysis !== undefined) {
									if (generalOptionsSettings.widgets.cbUseCurrentAnalysis.checked !== undefined) {
										generalOptionsSettings.widgets.cbUseCurrentAnalysis.checked = generalSettings.generalOptions.useCurrentAnalysis;
										settings.setValue(SpectrumQuality_Viewer.useCurrentAnalysisKey, generalSettings.generalOptions.useCurrentAnalysis);
									}
								}
							}
						}
					}
				}
			}

			//Set data to general options GUI - Second Options Tab
			//Load general options dialog
			resultsViewerOptionsSettings = SpectrumQuality_Viewer.getResultsViewerOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityResultsViewerSettings.ui');

			//Append general options to the generalSettings object
			//Check for undefined objects in order to forwards compatibility be guaranteed
			if (generalSettings !== undefined) {
				if (generalSettings.resultsViewerOptions !== undefined) {
					if (resultsViewerOptionsSettings !== undefined) {
						if (resultsViewerOptionsSettings.widgets !== undefined) {
							if (generalSettings.resultsViewerOptions.useSettings !== undefined) {
								if (resultsViewerOptionsSettings.widgets.gbRichText !== undefined) {
									if (resultsViewerOptionsSettings.widgets.gbRichText.checked !== undefined) {
										resultsViewerOptionsSettings.widgets.gbRichText.checked = generalSettings.resultsViewerOptions.useSettings;
										settings.setValue(SpectrumQuality_Viewer.richTextFlagKey, generalSettings.resultsViewerOptions.useSettings);
									}
								}
							}
							if (generalSettings.resultsViewerOptions.fontSize !== undefined) {
								if (resultsViewerOptionsSettings.widgets.sbFontSize !== undefined) {
									if (resultsViewerOptionsSettings.widgets.sbFontSize.value !== undefined) {
										resultsViewerOptionsSettings.widgets.sbFontSize.value = generalSettings.resultsViewerOptions.fontSize;
										settings.setValue(SpectrumQuality_Viewer.sizeFontKey, generalSettings.resultsViewerOptions.fontSize);
									}
								}
							}
							if (generalSettings.resultsViewerOptions.fontColor !== undefined) {
								if (resultsViewerOptionsSettings.widgets.colorComboBox !== undefined) {
									if (resultsViewerOptionsSettings.widgets.colorComboBox.currentIndex !== undefined) {
										resultsViewerOptionsSettings.widgets.colorComboBox.currentIndex = generalSettings.resultsViewerOptions.fontColor;
										settings.setValue(SpectrumQuality_Viewer.colorFontKey, generalSettings.resultsViewerOptions.fontColor);
									}
								}
							}
							if (generalSettings.resultsViewerOptions.fontType !== undefined) {
								if (resultsViewerOptionsSettings.widgets.fontComboBox !== undefined) {
									if (resultsViewerOptionsSettings.widgets.fontComboBox.currentIndex !== undefined) {
										resultsViewerOptionsSettings.widgets.fontComboBox.currentIndex = generalSettings.resultsViewerOptions.fontType;
										settings.setValue(SpectrumQuality_Viewer.typeFontKey, generalSettings.resultsViewerOptions.fontType);
									}
								}
							}
							if (generalSettings.resultsViewerOptions.textHighlight !== undefined) {
								if (resultsViewerOptionsSettings.widgets.cbTextHighlight !== undefined) {
									if (resultsViewerOptionsSettings.widgets.cbTextHighlight.checked !== undefined) {
										resultsViewerOptionsSettings.widgets.cbTextHighlight.checked = generalSettings.resultsViewerOptions.textHighlight;
										settings.setValue(SpectrumQuality_Viewer.useTestHightLightKey, generalSettings.resultsViewerOptions.textHighlight);
									}
								}
							}
						}
					}
				}
			}

			//Update the file information
			settings.setValue(SpectrumQuality_Viewer.generalDataFileKey, generalDataFile);
		}
	};

	SpectrumQuality_Viewer.prototype.saveSettings = function () {

		var dataFile, file, stream, myJSONText, generalSettings, generalOptionsSettings, resultsViewerOptionsSettings, data;

		//When the file is not empty we get the data and assign it.
		dataFile = FileDialog.getSaveFileName("*.data", "Save data", generalDataFile);
		if (dataFile !== "") {

			//Create generalSettings object
			generalSettings = {};
			generalSettings.acquisitionParameters = JSON.stringify(this.dialog.widgets.tableWidgetAcquisitionParameters.items);
			generalSettings.processingParameters = JSON.stringify(this.dialog.widgets.tableWidgetProcessingParameters.items);
			generalSettings.signalToNoiseFilterStatus = this.dialog.widgets.gbSignalToNoise.checked;
			generalSettings.signalFullSpectrum = this.dialog.widgets.rbSignalFullSpectrum.checked;
			generalSettings.signalFrom = this.dialog.widgets.leFromSignal.text;
			generalSettings.signalTo = this.dialog.widgets.leToSignal.text;
			generalSettings.noiseAutomatic = this.dialog.widgets.rbAutomaticNoise.checked;
			generalSettings.noiseFrom = this.dialog.widgets.leFromNoise.text;
			generalSettings.noiseTo = this.dialog.widgets.leToNoise.text;
			generalSettings.snrMinValue = this.dialog.widgets.leSignalNoiseMinimumValue.text;
			generalSettings.phaseFilterStatus = this.dialog.widgets.gbPhase.checked;
			generalSettings.phaseValue = this.dialog.widgets.spbxPhaseValue.value;
			generalSettings.peakFilterStatus = this.dialog.widgets.gbPeakWidth.checked;
			generalSettings.peakWidth = JSON.stringify(this.dialog.widgets.tableWidgetPeakWidth.items);
			generalSettings.peakIntensityFilterStatus = this.dialog.widgets.gbPeakIntensity.checked;
			generalSettings.peakIntensity = JSON.stringify(this.dialog.widgets.tableWidgetPeakIntensity.items);
			generalSettings.purityFilterStatus = this.dialog.widgets.gbPurity.checked;
			generalSettings.purityValue = this.dialog.widgets.spbxPurityValue.value;
			generalSettings.digitalResolutionFilterStatus = this.dialog.widgets.gbDigitalResolution.checked;
			generalSettings.digitalResolutionValue = this.dialog.widgets.spbxDigitalResolutionValue.value;
			generalSettings.currentIndexTab = this.dialog.widgets.tabWidget.currentIndex;

			//Get settings related to the general options
			generalOptionsSettings = SpectrumQuality_Viewer.getGeneralOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityGeneralSettings.ui');
			resultsViewerOptionsSettings = SpectrumQuality_Viewer.getResultsViewerOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityResultsViewerSettings.ui');

			//Appending options settings to the generalSettings object
			generalSettings.generalOptions = {};
			generalSettings.resultsViewerOptions = {};

			//General settings options population
			generalSettings.generalOptions.keepCurrentData = generalOptionsSettings.widgets.cbKeepCurrentData.checked;
			generalSettings.generalOptions.useCurrentAnalysis = generalOptionsSettings.widgets.cbUseCurrentAnalysis.checked;
			generalSettings.generalOptions.currentIndexOptionTab = generalOptionsSettings.widgets.tabWidget.currentIndex;
			if (generalOptionsSettings.widgets.tabWidget.count < 2) {
				data = settings.value(SpectrumQuality_Viewer.lastTabIndexViewedKey, "");
				if (data !== "" && !isNaN(data)) {
					generalSettings.generalOptions.currentIndexOptionTab = data;
				}
			}

			//Results viewer options population
			generalSettings.resultsViewerOptions.useSettings = resultsViewerOptionsSettings.widgets.gbRichText.checked;
			generalSettings.resultsViewerOptions.fontSize = resultsViewerOptionsSettings.widgets.sbFontSize.value;
			generalSettings.resultsViewerOptions.fontColor = resultsViewerOptionsSettings.widgets.colorComboBox.currentIndex;
			generalSettings.resultsViewerOptions.fontType = resultsViewerOptionsSettings.widgets.fontComboBox.currentIndex;
			generalSettings.resultsViewerOptions.textHighlight = resultsViewerOptionsSettings.widgets.cbTextHighlight.checked;

			//Write to a file
			file = new File(dataFile);
			generalDataFile = file.name;
			settings.setValue(SpectrumQuality_Viewer.generalDataFileKey, generalDataFile);
			file.open(File.WriteOnly);
			stream = new TextStream(file);
			stream.codec = "UTF-8";
			myJSONText = JSON.stringify(generalSettings);
			stream.write(myJSONText);
			stream.flush();
			file.close();
		}
	};

	SpectrumQuality_Viewer.prototype.generateSettings = function () {

		var result;

		result = this.validateGUIParameters();
		if (!result) {
			this.saveValuesToRegistry();
			MessageBox.information(qsTr("All the parameters have been saved successfully"));
		}
	};

	SpectrumQuality_Viewer.prototype.getProcessingParameters = function () {

		var spectra, processingParametersReport, processingParameterTemplate, processingParameters;

		//Get the processing parameters by using the template and ProcessingParametersReporter features
		spectra = SpectrumQuality_Viewer.getSelectedSpectra(1);
		if (spectra.length > 0) {
			processingParametersReport = new ProcessingParametersReporter(spectra[0].proc, 1, false, spectra[0]);
			processingParameterTemplate = SpectrumQuality_Engine.getProcessingReportTemplates(1);
			processingParameters = SpectrumQuality_Engine.getProcessingParameters(processingParameterTemplate);
			processingParameters = SpectrumQuality_Engine.getUniqueArray(processingParameters, false);
		}

		return processingParameters;
	};

	SpectrumQuality_Viewer.prototype.fillTableWidgetFromSettings = function (aTableWidget, aJSONString, aText, aAlignment, aFlags) {

		var properties, properties2, jsonObject, totalTableColumns, totalSettingsColumns, newColumns;

		//Get the number of columns from current tableWidget and settings object
		if (aTableWidget !== undefined && aJSONString !== undefined) {
			totalTableColumns = aTableWidget.columnCount;
			jsonObject = JSON.parse(aJSONString);
			for (properties in jsonObject) {
				if (jsonObject.hasOwnProperty(properties)) {
					totalSettingsColumns = Object.keys(jsonObject[properties]).length;
					break;
				}
			}

		//If the current table has more columns we have to care about compatibility with old settings
			newColumns = totalTableColumns - totalSettingsColumns;
			if (newColumns > 0) {
				for (properties in jsonObject) {
					if (jsonObject.hasOwnProperty(properties)) {
						for (properties2 in jsonObject[properties]) {
							if (jsonObject[properties].hasOwnProperty(properties2)) {
								if (Number(properties2) === (totalSettingsColumns - 1)) {
									//It appends to the settings object the new extra columns derived from new versions
									for (i = totalSettingsColumns; i < totalTableColumns; i++) {
										jsonObject[properties][i] = {};
										jsonObject[properties][i].text = aText;
										jsonObject[properties][i].textAlignment = aAlignment;
										jsonObject[properties][i].flags = aFlags;
									}
								}
							}
						}
					}
				}
			}

			//It assigns the items to the table widget
			aTableWidget.items = jsonObject;
		}
	};

	SpectrumQuality_Viewer.prototype.loadRegistryValues = function () {

		var data;

		//Acquisition parameters control
		data = settings.value(this.acquisitionParametersGUIKey, "");
		if (data !== "") {
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetAcquisitionParameters, data, "", 132, 35);
		}

		//Processing parameters control
		data = settings.value(this.processingParametersGUIKey, "");
		if (data !== "") {
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetProcessingParameters, data, "", 132, 35);
		}

		//Signal-to-Noise control
		data = settings.value(this.signalToNoiseStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			this.dialog.widgets.gbSignalToNoise.checked = data;
		}
		data = settings.value(this.signalFullSpectrumKey, "");
		if (data !== "") {
			data = (data === "true");
			if (data) {
				this.dialog.widgets.rbSignalFullSpectrum.checked = true;
			} else {
				this.dialog.widgets.rbRangeSignal.checked = true;
			}
		}
		data = settings.value(this.signalFromKey, "");
		if (data !== "") {
			this.dialog.widgets.leFromSignal.text = data;
		}
		data = settings.value(this.signalToKey, "");
		if (data !== "") {
			this.dialog.widgets.leToSignal.text = data;
		}
		data = settings.value(this.noiseAutomaticKey, "");
		if (data !== "") {
			data = (data === "true");
			if (data) {
				this.dialog.widgets.rbAutomaticNoise.checked = true;
			} else {
				this.dialog.widgets.rbRangeNoise.checked = true;
			}
		}
		data = settings.value(this.noiseFromKey, "");
		if (data !== "") {
			this.dialog.widgets.leFromNoise.text = data;
		}
		data = settings.value(this.noiseToKey, "");
		if (data !== "") {
			this.dialog.widgets.leToNoise.text = data;
		}
		data = settings.value(this.snrMinValueKey, "");
		if (data !== "") {
			this.dialog.widgets.leSignalNoiseMinimumValue.text = data;
		}

		//Phase control
		data = settings.value(this.phaseStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			this.dialog.widgets.gbPhase.checked = data;
		}
		data = settings.value(this.phaseValueKey, "");
		if (data !== "") {
			this.dialog.widgets.spbxPhaseValue.value = data;
		}

		//Peak width control
		data = settings.value(this.peakStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			this.dialog.widgets.gbPeakWidth.checked = data;
		}
		data = settings.value(this.peakWidthGUIKey, "");
		if (data !== "") {
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetPeakWidth, data, "", 132, 35);
		}

		//Intensity control
		data = settings.value(this.peakIntensityStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			this.dialog.widgets.gbPeakIntensity.checked = data;
		}
		data = settings.value(this.peakIntensityGUIKey, "");
		if (data !== "") {
			this.fillTableWidgetFromSettings(this.dialog.widgets.tableWidgetPeakIntensity, data, "", 132, 35);
		}

		//Purity control
		data = settings.value(this.purityStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			this.dialog.widgets.gbPurity.checked = data;
		}
		data = settings.value(this.purityValueKey, "");
		if (data !== "") {
			this.dialog.widgets.spbxPurityValue.value = data;
		}

		//Digital Resolution control
		data = settings.value(this.digitalResolutionStatusKey, "");
		if (data !== "") {
			data = (data === "true");
			this.dialog.widgets.gbDigitalResolution.checked = data;
		}
		data = settings.value(this.digitalResolutionValueKey, "");
		if (data !== "") {
			this.dialog.widgets.spbxDigitalResolutionValue.value = data;
		}
		generalDataFile = settings.value(SpectrumQuality_Viewer.generalDataFileKey, Dir.home() + "/spectrumQuality.data");

		//Tab Control
		data = settings.value(SpectrumQuality_Viewer.lastTabKey, "");
		if (data !== "" && !isNaN(data)) {
			this.dialog.widgets.tabWidget.currentIndex = data;
		}
	};

	SpectrumQuality_Viewer.prototype.saveValuesToRegistry = function () {

		var dataObject, generalSettingsDialog;

		//SQA main dialog
		if (this.dialog !== undefined && this.dialog.widgets !== undefined) {

			//Acquisition parameters control
			dataObject = JSON.stringify(SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetAcquisitionParameters.items, this.acquisitionParameter.checkBoxParameter, this.acquisitionParameter.parameterParameter, this.acquisitionParameter.conditionParameter, this.acquisitionParameter.valueParameter));
			settings.setValue(this.acquisitionParametersKey, dataObject);
			dataObject = JSON.stringify(this.dialog.widgets.tableWidgetAcquisitionParameters.items);
			settings.setValue(this.acquisitionParametersGUIKey, dataObject);

			//Processing parameters control
			dataObject = JSON.stringify(SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetProcessingParameters.items, this.processingParameter.checkBoxParameter, this.processingParameter.parameterParameter, this.processingParameter.conditionParameter, this.processingParameter.valueParameter));
			settings.setValue(this.processingParametersKey, dataObject);
			dataObject = JSON.stringify(this.dialog.widgets.tableWidgetProcessingParameters.items);
			settings.setValue(this.processingParametersGUIKey, dataObject);

			//Signal-to-Noise control
			settings.setValue(this.signalToNoiseStatusKey, this.dialog.widgets.gbSignalToNoise.checked);
			settings.setValue(this.signalFullSpectrumKey, this.dialog.widgets.rbSignalFullSpectrum.checked);
			settings.setValue(this.signalFromKey, this.dialog.widgets.leFromSignal.text);
			settings.setValue(this.signalToKey, this.dialog.widgets.leToSignal.text);
			settings.setValue(this.noiseAutomaticKey, this.dialog.widgets.rbAutomaticNoise.checked);
			settings.setValue(this.noiseFromKey, this.dialog.widgets.leFromNoise.text);
			settings.setValue(this.noiseToKey, this.dialog.widgets.leToNoise.text);
			settings.setValue(this.snrMinValueKey, this.dialog.widgets.leSignalNoiseMinimumValue.text);

			//Phase control
			settings.setValue(this.phaseStatusKey, this.dialog.widgets.gbPhase.checked);
			settings.setValue(this.phaseConditionKey, SpectrumQuality_Engine.phaseErrorCondition);
			settings.setValue(this.phaseValueKey, this.dialog.widgets.spbxPhaseValue.value);

			//Peak width control
			settings.setValue(this.peakStatusKey, this.dialog.widgets.gbPeakWidth.checked);
			dataObject = JSON.stringify(SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetPeakWidth.items, this.peakWidth.checkBoxParameter, this.peakWidth, this.peakWidth.conditionParameter, this.peakWidth.valueParameter));
			settings.setValue(this.peakWidthKey, dataObject);
			dataObject = JSON.stringify(this.dialog.widgets.tableWidgetPeakWidth.items);
			settings.setValue(this.peakWidthGUIKey, dataObject);

			//Intensity control
			settings.setValue(this.peakIntensityStatusKey, this.dialog.widgets.gbPeakIntensity.checked);
			dataObject = JSON.stringify(SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetPeakIntensity.items, this.peakIntensity.checkBoxParameter, this.peakIntensity, this.peakIntensity.conditionParameter, this.peakIntensity.valueParameter));
			settings.setValue(this.peakIntensityKey, dataObject);
			dataObject = JSON.stringify(this.dialog.widgets.tableWidgetPeakIntensity.items);
			settings.setValue(this.peakIntensityGUIKey, dataObject);

			//Purity control
			settings.setValue(this.purityStatusKey, this.dialog.widgets.gbPurity.checked);
			settings.setValue(this.purityConditionKey, SpectrumQuality_Engine.purityCondition);
			settings.setValue(this.purityValueKey, this.dialog.widgets.spbxPurityValue.value);

			//Digital resolution control
			settings.setValue(this.digitalResolutionStatusKey, this.dialog.widgets.gbDigitalResolution.checked);
			settings.setValue(this.digitalResolutionConditionKey, SpectrumQuality_Engine.digitalResolutionCondition);
			settings.setValue(this.digitalResolutionValueKey, this.dialog.widgets.spbxDigitalResolutionValue.value);

			//Tab control
			settings.setValue(SpectrumQuality_Viewer.lastTabKey, this.dialog.widgets.tabWidget.currentIndex);
		}

		//SQA general options dialog
		generalSettingsDialog = SpectrumQuality_Viewer.getGeneralOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityGeneralSettings.ui');
		if (generalSettingsDialog !== undefined) {
			if (generalSettingsDialog.widgets !== undefined) {
				settings.setValue(SpectrumQuality_Viewer.keepCurrentDataKey, generalSettingsDialog.widgets.cbKeepCurrentData.checked);
				settings.setValue(SpectrumQuality_Viewer.useCurrentAnalysisKey, generalSettingsDialog.widgets.cbUseCurrentAnalysis.checked);
			}
		}

	};

	SpectrumQuality_Viewer.prototype.loadWidget = function () {

		//Load entries from registry
		this.loadRegistryValues();

		//Manage Buttons regarding the acquisition parameters table
		this.dialog.widgets.tbAddAcquisitionParameters.enabled = true;
		this.dialog.widgets.tbDeleteAcquisitionParameters.enabled = false;
		this.dialog.widgets.tbCheckAllAcquisitionParameters.enabled = false;
		this.dialog.widgets.tbUncheckAllAcquisitionParameters.enabled = false;

		this.dialog.widgets.tbAddProcessingParameters.enabled = true;
		this.dialog.widgets.tbDeleteProcessingParameters.enabled = false;
		this.dialog.widgets.tbCheckAllProcessingParameters.enabled = false;
		this.dialog.widgets.tbUncheckAllProcessingParameters.enabled = false;

		this.dialog.widgets.tbAddPeakWidth.enabled = true;
		this.dialog.widgets.tbDeletePeakWidth.enabled = false;
		this.dialog.widgets.tbCheckAllPeakWidth.enabled = false;
		this.dialog.widgets.tbUncheckAllPeakWidth.enabled = false;

		this.dialog.widgets.tbAddPeakIntensity.enabled = true;
		this.dialog.widgets.tbDeletePeakIntensity.enabled = false;
		this.dialog.widgets.tbCheckAllPeakIntensity.enabled = false;
		this.dialog.widgets.tbUncheckAllPeakIntensity.enabled = false;

		//Update check and uncheck buttons
		if (this.acquisitionParameter.totalRowsLoaded < this.acquisitionParameter.tableWidget.rowCount) {
			this.acquisitionParameter.tbCheckAll.enabled = true;
		}
		if (this.acquisitionParameter.totalRowsLoaded > 0) {
			this.acquisitionParameter.tbUncheckAll.enabled = true;
		}
		if (this.processingParameter.totalRowsLoaded < this.processingParameter.tableWidget.rowCount) {
			this.processingParameter.tbCheckAll.enabled = true;
		}
		if (this.processingParameter.totalRowsLoaded > 0) {
			this.processingParameter.tbUncheckAll.enabled = true;
		}
		if (this.peakWidth.totalRowsLoaded < this.peakWidth.tableWidget.rowCount) {
			this.peakWidth.tbCheckAll.enabled = true;
		}
		if (this.peakWidth.totalRowsLoaded > 0) {
			this.peakWidth.tbUncheckAll.enabled = true;
		}
		if (this.peakIntensity.totalRowsLoaded < this.peakIntensity.tableWidget.rowCount) {
			this.peakIntensity.tbCheckAll.enabled = true;
		}
		if (this.peakIntensity.totalRowsLoaded > 0) {
			this.peakIntensity.tbUncheckAll.enabled = true;
		}

		//Initialize the loaded rows number
		this.acquisitionParameter.totalRowsLoaded = -1;
		this.processingParameter.totalRowsLoaded = -1;
		this.peakWidth.totalRowsLoaded = -1;
		this.peakIntensity.totalRowsLoaded = -1;

		//Manage initialization of radio buttons
		if (this.dialog.widgets.rbSignalFullSpectrum.checked) {
			this.dialog.widgets.leFromSignal.enabled = false;
			this.dialog.widgets.lbToSignal.enabled = false;
			this.dialog.widgets.leToSignal.enabled = false;
			this.dialog.widgets.lbPPMSignal.enabled = false;
		}

		if (this.dialog.widgets.rbAutomaticNoise.checked) {
			this.dialog.widgets.leFromNoise.enabled = false;
			this.dialog.widgets.lbToNoise.enabled = false;
			this.dialog.widgets.leToNoise.enabled = false;
			this.dialog.widgets.lbPPMNoise.enabled = false;
		}
	};

	SpectrumQuality_Viewer.prototype.selectionChanged = function () {

		var selectedItems;

		selectedItems = this.tableWidget.selectedItems().length / this.tableWidget.columnCount;
		this.tbDelete.enabled = false;
		if (selectedItems > 0) {
			this.tbDelete.enabled = true;
		}
	};

	SpectrumQuality_Viewer.prototype.checkAllRows = function () {

		var i, items;

		this.tableWidget.cellChanged.disconnect(this, SpectrumQuality_Viewer.cellRowsChanged);
		items = this.tableWidget.items;
		for (i = 0; i < items.length; i++) {
			if (items[i][this.checkBoxParameter].checkState !== 2) {
				items[i][this.checkBoxParameter].checkState = 2;
				this.totalRowsChecked++;
			}
		}
		this.tbUncheckAll.enabled = true;
		this.tbCheckAll.enabled = false;
		this.tableWidget.items = items;
		this.tableWidget.cellChanged.connect(this, SpectrumQuality_Viewer.cellRowsChanged);
	};

	SpectrumQuality_Viewer.prototype.uncheckAllRows = function () {

		var i, items;

		this.tableWidget.cellChanged.disconnect(this, SpectrumQuality_Viewer.cellRowsChanged);
		items = this.tableWidget.items;
		for (i = 0; i < items.length; i++) {
			if (items[i][this.checkBoxParameter].checkState !== 0) {
				items[i][this.checkBoxParameter].checkState = 0;
				this.totalRowsChecked--;
			}
		}
		this.tbUncheckAll.enabled = false;
		this.tbCheckAll.enabled = true;
		this.tableWidget.items = items;
		this.tableWidget.cellChanged.connect(this, SpectrumQuality_Viewer.cellRowsChanged);
	};

	SpectrumQuality_Viewer.prototype.loadParametersTable = function (aTable, aSpectrum, aSourceTable) {

		var i, j, items, parameters, parametersArray, currentParameter, found, sourceItems, previousParameter;

		//Initialize vars
		this.addParametersTable.totalRowsChecked = 0;
		sourceItems = aSourceTable.items;

		//Filter the parameters before filling the table
		if (this.reflexion === "acquisitionParameter") {
			parameters = aSpectrum.paramNames();
		} else if (this.reflexion === "processingParameter") {
			parameters = this.getProcessingParameters();
		}
		parametersArray = [];
		for (i = 0; i < parameters.length; i++) {
			found = false;
			currentParameter = parameters[i];
			if (sourceItems !== undefined) {
				//Check the parameter is not already stored at the main table
				for (j = 0; j < sourceItems.length; j++) {
					previousParameter = sourceItems[j][this.parameterParameter].text;
					if (previousParameter === currentParameter) {
						found = true;
						break;
					}
				}
			}

			//If all the conditions have been met, then insert the parameter
			if (!found) {
				aTable.insertRow(aTable.items.length);
				parametersArray.push(currentParameter);
			}
		}

		//Fill table spectra with the above information
		items = aTable.items;
		for (i = 0; i < parametersArray.length; i++) {
			currentParameter = parametersArray[i];
			items[i][this.addParametersTable.checkBoxParameter].text = "";
			items[i][this.addParametersTable.checkBoxParameter].flags = 49;
			items[i][this.addParametersTable.checkBoxParameter].checkState = 0;
			items[i][this.addParametersTable.parameterParameter].text = currentParameter;
			items[i][this.addParametersTable.parameterParameter].flags = 33;
			items[i][this.addParametersTable.parameterParameter].textAlignment = 132;
			if (this.reflexion === "processingParameter") {
				items[i][this.addParametersTable.valueParameter].text = aSpectrum.proc.getParameter(currentParameter);
			} else {
				items[i][this.addParametersTable.valueParameter].text = "";
			}
			items[i][this.addParametersTable.valueParameter].flags = 35;
			items[i][this.addParametersTable.valueParameter].textAlignment = 132;
		}
		aTable.enabled = true;
		aTable.items = items;
		aTable.resizeColumnToContents(0);
		aTable.resizeColumnToContents(1);

		//Active signal in order to know when a checkbox has been checked or unchecked
		this.addParametersTable.tableWidget.cellChanged.connect(this.addParametersTable, SpectrumQuality_Viewer.cellRowsChanged);

		//Manage check and uncheck buttons related to the main table
		if (this.addParametersTable.totalRowsChecked > 0) {
			this.addParametersTable.tbUncheckAll.enabled = true;
		}
		if (this.addParametersTable.totalRowsChecked !== aTable.rowCount) {
			this.addParametersTable.tbCheckAll.enabled = true;
		}

		//Manage Check All Button Signal
		this.addParametersTable.tbCheckAll.clicked.connect(this.addParametersTable, this.checkAllRows);

		//Uncheck all Parameters
		this.addParametersTable.tbUncheckAll.clicked.connect(this.addParametersTable, this.uncheckAllRows);
	};

	SpectrumQuality_Viewer.prototype.addParameters = function (aSpectrum) {

		var i, dialog, showDialog, itemsSource, itemsDestination, totalItems, offset;

		//Create object and manage dialog tool buttons
		dialog = Application.loadUiFile('ricares:SpectrumQualityAddParameters.ui');
		this.addParametersTable.tableWidget = dialog.widgets.tableWidgetParameters;
		this.addParametersTable.tbCheckAll = dialog.widgets.tbCheckAll;
		this.addParametersTable.tbUncheckAll = dialog.widgets.tbUncheckAll;
		this.addParametersTable.tbCheckAll.enabled = false;
		this.addParametersTable.tbUncheckAll.enabled = false;
		showDialog = true;

		//Get parameters for active spectrum
		this.loadParametersTable(this.addParametersTable.tableWidget, aSpectrum, this.tableWidget);

		//The exec() print windows. This means we need to have already loaded the previous signal which manage events thanks to connected method.
		while (showDialog) {
			//Check if cancel button is pulsed by user
			if (!dialog.exec()) {
				return;
			}

			showDialog = false;
		}

		//Fill the main table with the data of the parameters table.
		//First of all, we create the new rows and then we fill them
		itemsSource = dialog.widgets.tableWidgetParameters.items;
		for (i = 0; i < itemsSource.length; i++) {
			if (itemsSource[i][this.addParametersTable.checkBoxParameter].checkState === 2) {
				this.tableWidget.insertRow(this.tableWidget.items.rowCount);
			}
		}

		//Fill new rows with source data
		offset = 0;
		totalItems = dialog.widgets.tableWidgetParameters.rowCount;
		itemsDestination = this.tableWidget.items;

		//Disconnect signal in order to avoid bad counts when data is being loaded
		this.tableWidget.cellChanged.disconnect(this, SpectrumQuality_Viewer.cellRowsChanged);
		for (i = 0; i < itemsSource.length; i++) {
			if (itemsSource[i][this.checkBoxParameter].checkState === 2) {
				itemsDestination[offset][this.checkBoxParameter].text = "";
				itemsDestination[offset][this.checkBoxParameter].flags = 49;
				itemsDestination[offset][this.checkBoxParameter].checkState = 2;
				itemsDestination[offset][this.parameterParameter].text = itemsSource[i][this.addParametersTable.parameterParameter].text;
				itemsDestination[offset][this.parameterParameter].textAlignment = 132;
				itemsDestination[offset][this.parameterParameter].flags = 35;
				itemsDestination[offset][this.conditionParameter].text = "=";
				itemsDestination[offset][this.conditionParameter].textAlignment = 132;
				itemsDestination[offset][this.conditionParameter].flags = 33;
				itemsDestination[offset][this.valueParameter].text = itemsSource[i][this.addParametersTable.valueParameter].text;
				itemsDestination[offset][this.valueParameter].textAlignment = 132;
				itemsDestination[offset][this.valueParameter].flags = 35;
				offset++;
				this.totalRowsChecked++;
			}
		}

		this.tableWidget.items = itemsDestination;
		this.tableWidget.cellChanged.connect(this, SpectrumQuality_Viewer.cellRowsChanged);

		if (totalItems === offset) {
			this.tbAdd.enabled = false;
		}
	};

	SpectrumQuality_Viewer.prototype.addRow = function () {

		var items, row, spectrum;

		//Get active spectrum
		spectrum = nmr.activeSpectrum();

		//Show an auxiliary parameters table only for acquisition and processing parameters tests
		//Furthermore, the current spectrum must be both valid and 1D
		if (!spectrum.isValid() || this.reflexion === "peakWidth" || this.reflexion === "intensity" || (spectrum.isValid() && spectrum.dimCount === 2)) {

			//Disconnect signal in order to avoid bad counts when data is being loaded
			this.tableWidget.cellChanged.disconnect(this, SpectrumQuality_Viewer.cellRowsChanged);

			//Insert table rows before fill the table with the data
			row = this.tableWidget.items.length;
			this.tableWidget.insertRow(row);

			//Fill table spectra with the above information
			items = this.tableWidget.items;
			items[row][this.checkBoxParameter].text = "";
			items[row][this.checkBoxParameter].flags = 49;
			items[row][this.checkBoxParameter].checkState = 2;
			if (this.reflexion === "peakWidth") {
				items[row][this.fromPPM].text = "";
				items[row][this.fromPPM].textAlignment = 132;
				items[row][this.fromPPM].flags = 35;
				items[row][this.toPPM].text = "";
				items[row][this.toPPM].textAlignment = 132;
				items[row][this.toPPM].flags = 35;
				items[row][this.peakType].text = "";
				items[row][this.peakType].textAlignment = 132;
				items[row][this.peakType].flags = 35;
				items[row][this.atHeight].text = "";
				items[row][this.atHeight].textAlignment = 132;
				items[row][this.atHeight].flags = 35;
				items[row][this.asymmetryConditionParameter].text = "";
				items[row][this.asymmetryConditionParameter].textAlignment = 132;
				items[row][this.asymmetryConditionParameter].flags = 33;
				items[row][this.asymmetryValueParameter].text = "";
				items[row][this.asymmetryValueParameter].textAlignment = 132;
				items[row][this.asymmetryValueParameter].flags = 35;
			} else if (this.reflexion === "intensity") {
				items[row][this.fromPPM].text = "";
				items[row][this.fromPPM].textAlignment = 132;
				items[row][this.fromPPM].flags = 35;
				items[row][this.toPPM].text = "";
				items[row][this.toPPM].textAlignment = 132;
				items[row][this.toPPM].flags = 35;
				items[row][this.peakType].text = "";
				items[row][this.peakType].textAlignment = 132;
				items[row][this.peakType].flags = 35;
			} else {
				items[row][this.parameterParameter].text = "";
				items[row][this.parameterParameter].textAlignment = 132;
				items[row][this.parameterParameter].flags = 35;
			}
			items[row][this.conditionParameter].text = "";
			items[row][this.conditionParameter].textAlignment = 132;
			items[row][this.conditionParameter].flags = 33;
			items[row][this.valueParameter].text = "";
			items[row][this.valueParameter].textAlignment = 132;
			items[row][this.valueParameter].flags = 35;
			this.totalRowsChecked++;

			this.tableWidget.enabled = true;
			this.tableWidget.items = items;
			this.tableWidget.cellChanged.connect(this, SpectrumQuality_Viewer.cellRowsChanged);

		} else {
			this.addParameters(spectrum);
		}

		//Manage smart buttons and adapt widget
		this.tableWidget.resizeColumnToContents(this.checkBoxParameter);
		this.tbDelete.enabled = false;
		this.tbCheckAll.enabled = false;
		this.tbUncheckAll.enabled = false;
		if (this.totalRowsChecked > 0) {
			this.tbUncheckAll.enabled = true;
		}
		if (this.totalRowsChecked !== this.tableWidget.rowCount) {
			this.tbCheckAll.enabled = true;
		}
	};

	SpectrumQuality_Viewer.prototype.deleteRows = function () {

		var i, items, rowsToDelete;

		this.tableWidget.cellChanged.disconnect(this, SpectrumQuality_Viewer.cellRowsChanged);
		items = this.tableWidget.selectedItems();

		//Get the rows to delete by using the items in desc order.
		rowsToDelete = SpectrumQuality_Engine.getUniqueArray(items);
		rowsToDelete.sort(function (a, b) {
			return b.row - a.row;
		});

		//Get the new totalRowsChecked state
		for (i = 0; i < items.length; i++) {
			if (items[i].checkState === 2) {
				this.totalRowsChecked--;
			}
		}

		//Now delete the selected rows
		for (i = 0; i < rowsToDelete.length; i++) {
			this.tableWidget.removeRow(rowsToDelete[i].row);
		}

		this.tableWidget.cellChanged.connect(this, SpectrumQuality_Viewer.cellRowsChanged);
		this.tbAdd.enabled = true;
		this.tbDelete.enabled = false;
		this.tbCheckAll.enabled = false;
		this.tbUncheckAll.enabled = false;

		if (this.tableWidget.rowCount > 0) {
			this.tbDelete.enabled = true;
			if (this.totalRowsChecked > 0) {
				this.tbUncheckAll.enabled = true;
			}
			if (this.totalRowsChecked < this.tableWidget.rowCount) {
				this.tbCheckAll.enabled = true;
			}
		}
	};

	SpectrumQuality_Viewer.prototype.showTabIndex = function (aTabWidget, aTabIndex) {

		var tabCounter;

		if (aTabWidget !== undefined) {
			if (aTabIndex !== undefined) {
				if (!isNaN(aTabIndex)) {
					if (aTabIndex > -1) {
						if (aTabWidget.currentIndex !== undefined) {
							if (aTabWidget.count !== undefined) {
								tabCounter = aTabWidget.count;
								if (!isNaN(tabCounter)) {
									if (aTabIndex < tabCounter) {
										aTabWidget.setCurrentIndex(aTabIndex);
									}
								}
							}
						}
					}
				}
			}
		}
	};

	SpectrumQuality_Viewer.prototype.getTestTabIndex = function (aTabWidget, aTextID) {

		var i, tabCounter, tabIndex, currentTabText;

		tabIndex = -1;
		try {
			if (aTabWidget !== undefined) {
				if (aTextID !== undefined) {
					if (typeof (aTextID) === "string") {
						if (aTextID !== "") {
							if (aTabWidget.count !== undefined) {
								tabCounter = aTabWidget.count;
								if (!isNaN(tabCounter)) {
									for (i = 0; i < tabCounter; i++) {
										currentTabText = aTabWidget.tabText(i);
										if (aTextID === aTabWidget.currentTabText) {
											tabIndex = aTabWidget.currentIndex;
											break;
										}
									}
								}
							}
						}
					}
				}
			}

		//If the version is lower than implementation revision (r25316) for the tabText function it returns -1
		//The exception management allows that a dependency is not created in the minimum version of Mnova for the tabText function
		//The -1 value will act as a token to use a numbering with the mapping instead.
		} catch (e) {
			return tabIndex;
		}

		return tabIndex;
	};

	SpectrumQuality_Viewer.prototype.validateGUIParameters = function () {

		var result, flagAcquisitionParametersTestUsed, flagProcessingParametersTestUsed,
			flagSNRTestUsed, flagPhaseTestUsed, flagPeakWidthTestUsed, flagIntensityTestUsed,
			flagPurityTestUsed, flagDigitalResolutionTestUsed, tabIndex, stringTest, stringTestID,
			rowNumberWithFieldNotFilled, rowNumberWithNotNumberValue;

		result = false;
		flagAcquisitionParametersTestUsed = false;
		flagProcessingParametersTestUsed = false;
		flagSNRTestUsed = false;
		flagPhaseTestUsed = false;
		flagPeakWidthTestUsed = false;
		flagIntensityTestUsed = false;
		flagPurityTestUsed = false;
		flagDigitalResolutionTestUsed = false;

		//Acquisition parameters filter checking
		if (this.dialog.widgets.tableWidgetAcquisitionParameters.rowCount > 0) {
			stringTestID = SpectrumQuality_Viewer.testNameID.AcquisitionParameters;
			stringTest = qsTr("{0} Test:".format(stringTestID));
			flagAcquisitionParametersTestUsed = true;
			tabIndex = this.getTestTabIndex(this.dialog.widgets.tabWidget, stringTestID);
			if (tabIndex === -1) {
				tabIndex = SpectrumQuality_Viewer.tabsIndexAndTestMapping.AcquisitionParameters;
			}

			//Check for present data
			if (!result) {
				rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.acquisitionParameter.tableWidget, this.acquisitionParameter.parameterParameter, this.acquisitionParameter.checkBoxParameter, this.acquisitionParameter.numericConstraintForParameterParameter);
				if (rowNumberWithFieldNotFilled > 0) {
					this.showTabIndex(this.dialog.widgets.tabWidget, this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the parameter field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
					result = true;
					flagAcquisitionParametersTestUsed = false;
				}
			}

			if (!result) {
				rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.acquisitionParameter.tableWidget, this.acquisitionParameter.conditionParameter, this.acquisitionParameter.checkBoxParameter, this.acquisitionParameter.numericConstraintForConditionParameter);
				if (rowNumberWithFieldNotFilled > 0) {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the condition field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
					result = true;
					flagAcquisitionParametersTestUsed = false;
				}
			}

			if (!result && SpectrumQuality_Viewer.getTotalRowsChecked(this.acquisitionParameter.tableWidget, this.acquisitionParameter.checkBoxParameter) === 0) {
				flagAcquisitionParametersTestUsed = false;
			}
		}

		//Processing parameters filter checking
		if (this.dialog.widgets.tableWidgetProcessingParameters.rowCount > 0) {
			stringTestID = SpectrumQuality_Viewer.testNameID.ProcessingParameters;
			stringTest = qsTr("{0} Test:".format(stringTestID));
			flagProcessingParametersTestUsed = true;
			tabIndex = this.getTestTabIndex(this.dialog.widgets.tabWidget, stringTestID);
			if (tabIndex === -1) {
				tabIndex = SpectrumQuality_Viewer.tabsIndexAndTestMapping.ProcessingParameters;
			}

			//Check for present data
			if (!result) {
				rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.processingParameter.tableWidget, this.processingParameter.parameterParameter, this.processingParameter.checkBoxParameter, this.processingParameter.numericConstraintForParameterParameter);
				if (rowNumberWithFieldNotFilled > 0) {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the parameter field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
					result = true;
					flagProcessingParametersTestUsed = false;
				}
			}

			if (!result) {
				rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.processingParameter.tableWidget, this.processingParameter.conditionParameter, this.processingParameter.checkBoxParameter, this.processingParameter.numericConstraintForConditionParameter);
				if (rowNumberWithFieldNotFilled > 0) {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the condition field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
					result = true;
					flagProcessingParametersTestUsed = false;
				}
			}

			if (!result && SpectrumQuality_Viewer.getTotalRowsChecked(this.processingParameter.tableWidget, this.processingParameter.checkBoxParameter) === 0) {
				flagProcessingParametersTestUsed = false;
			}
		}

		//SNR filter checking
		if (this.dialog.widgets.gbSignalToNoise.checked) {
			stringTestID = SpectrumQuality_Viewer.testNameID.SignalToNoise;
			stringTest = qsTr("{0} Test:".format(stringTestID));
			flagSNRTestUsed = true;
			tabIndex = this.getTestTabIndex(this.dialog.widgets.tabWidget, stringTestID);
			if (tabIndex === -1) {
				tabIndex = SpectrumQuality_Viewer.tabsIndexAndTestMapping.SignalToNoise;
			}

			if (this.dialog.widgets.rbRangeSignal.checked || !this.dialog.widgets.rbAutomaticNoise.enabled) {
				if (!result && this.dialog.widgets.leFromSignal.text.trim() === "") {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the from ppm signal field".format(stringTest)));
					this.dialog.widgets.leFromSignal.setFocus();
					result = true;
					flagSNRTestUsed = false;
				} else if (!result && isNaN(this.dialog.widgets.leFromSignal.text)) {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} the from ppm signal value must be a number".format(stringTest)));
					this.dialog.widgets.leFromSignal.setFocus();
					result = true;
					flagSNRTestUsed = false;
				}
				if (!result && this.dialog.widgets.leToSignal.text.trim() === "") {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the to ppm signal field".format(stringTest)));
					this.dialog.widgets.leToSignal.setFocus();
					result = true;
					flagSNRTestUsed = false;
				} else if (!result && isNaN(this.dialog.widgets.leToSignal.text)) {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} the to ppm signal value must be a number".format(stringTest)));
					this.dialog.widgets.leToSignal.setFocus();
					result = true;
					flagSNRTestUsed = false;
				}
			}
			if (this.dialog.widgets.rbRangeNoise.checked) {
				if (!result && this.dialog.widgets.leFromNoise.text.trim() === "") {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the from ppm noise field".format(stringTest)));
					this.dialog.widgets.leFromNoise.setFocus();
					result = true;
					flagSNRTestUsed = false;
				} else if (!result && isNaN(this.dialog.widgets.leFromNoise.text)) {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} the from ppm noise value must be a number".format(stringTest)));
					this.dialog.widgets.leFromNoise.setFocus();
					result = true;
					flagSNRTestUsed = false;
				}
				if (!result && this.dialog.widgets.leToNoise.text.trim() === "") {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} a value is needed in the to ppm noise field".format(stringTest)));
					this.dialog.widgets.leToNoise.setFocus();
					result = true;
					flagSNRTestUsed = false;
				} else if (!result && isNaN(this.dialog.widgets.leToNoise.text)) {
					this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
					MessageBox.critical(qsTr("{0} the to ppm noise value must be a number".format(stringTest)));
					this.dialog.widgets.leToNoise.setFocus();
					result = true;
					flagSNRTestUsed = false;
				}
			}
			if (this.dialog.widgets.leSignalNoiseMinimumValue.text !== "") {
				if (this.dialog.widgets.leSignalNoiseMinimumValue.text.length > 0) {
					if (!result && isNaN(this.dialog.widgets.leSignalNoiseMinimumValue.text)) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} the minimum value parameter must be a number".format(stringTest)));
						this.dialog.widgets.leSignalNoiseMinimumValue.setFocus();
						result = true;
						flagSNRTestUsed = false;
					} else if (!result && this.dialog.widgets.leSignalNoiseMinimumValue.text.trim() === "") {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} the minimum value parameter contains white space characters".format(stringTest)));
						this.dialog.widgets.leSignalNoiseMinimumValue.setFocus();
						result = true;
						flagSNRTestUsed = false;
					}
				}
			}
		}

		//Phase filter checking
		if (this.dialog.widgets.gbPhase.checked) {
			flagPhaseTestUsed = true;
		}

		//Peak filter checking
		if (this.dialog.widgets.gbPeakWidth.checked) {
			stringTestID = SpectrumQuality_Viewer.testNameID.PeakWidth;
			stringTest = qsTr("{0} Test:".format(stringTestID));
			flagPeakWidthTestUsed = true;
			tabIndex = this.getTestTabIndex(this.dialog.widgets.tabWidget, stringTestID);
			if (tabIndex === -1) {
				tabIndex = SpectrumQuality_Viewer.tabsIndexAndTestMapping.PeakWidth;
			}

			if (this.dialog.widgets.tableWidgetPeakWidth.rowCount > 0) {
				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakWidth.tableWidget, this.peakWidth.fromPPM, this.peakWidth.checkBoxParameter, this.peakWidth.numericConstraintForFromPPM);
					if (rowNumberWithFieldNotFilled > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the from ppm field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakWidth.tableWidget, this.peakWidth.fromPPM, this.peakWidth.checkBoxParameter);
					if (rowNumberWithNotNumberValue > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} the from ppm field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakWidth.tableWidget, this.peakWidth.toPPM, this.peakWidth.checkBoxParameter, this.peakWidth.numericConstraintForToPPM);
					if (rowNumberWithFieldNotFilled > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the to ppm field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakWidth.tableWidget, this.peakWidth.toPPM, this.peakWidth.checkBoxParameter);
					if (rowNumberWithNotNumberValue > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} the to ppm field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakWidth.tableWidget, this.peakWidth.peakType, this.peakWidth.checkBoxParameter, this.peakWidth.numericConstraintForPeakType);
					if (rowNumberWithFieldNotFilled > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the peak type field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakWidth.tableWidget, this.peakWidth.atHeight, this.peakWidth.checkBoxParameter, this.peakWidth.numericConstraintForAtHeight);
					if (rowNumberWithFieldNotFilled > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the at height field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakWidth.tableWidget, this.peakWidth.atHeight, this.peakWidth.checkBoxParameter);
					if (rowNumberWithNotNumberValue > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} the at height field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakWidth.tableWidget, this.peakWidth.valueParameter, this.peakWidth.checkBoxParameter, this.peakWidth.numericConstraintForValueParameter, this.peakWidth.conditionParameter);
					if (rowNumberWithFieldNotFilled <= 0) {
						rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakWidth.tableWidget, this.peakWidth.valueParameter, this.peakWidth.checkBoxParameter);
						if (rowNumberWithNotNumberValue > 0) {
							this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
							MessageBox.critical(qsTr("{0} the peak value field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
							result = true;
							flagPeakWidthTestUsed = false;
						}
					} else {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the peak value field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakWidth.tableWidget, this.peakWidth.asymmetryValueParameter, this.peakWidth.checkBoxParameter, this.peakWidth.numericConstraintForAsymmetryValueParameter, this.peakWidth.asymmetryConditionParameter);
					if (rowNumberWithFieldNotFilled <= 0) {
						rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakWidth.tableWidget, this.peakWidth.asymmetryValueParameter, this.peakWidth.checkBoxParameter);
						if (rowNumberWithNotNumberValue > 0) {
							this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
							MessageBox.critical(qsTr("{0} the asymmetry value field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
							result = true;
							flagPeakWidthTestUsed = false;
						}
					} else {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the asymmetry value field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result && SpectrumQuality_Viewer.getTotalRowsChecked(this.peakWidth.tableWidget, this.peakWidth.checkBoxParameter) === 0) {
					flagPeakWidthTestUsed = false;
				}
			} else {
				this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
				MessageBox.critical(qsTr("{0} a row is needed".format(stringTest)));
				this.dialog.widgets.tableWidgetPeakWidth.setFocus();
				result = true;
				flagPeakWidthTestUsed = false;
			}
		}

		//Intensity filter checking
		if (this.dialog.widgets.gbPeakIntensity.checked) {
			stringTestID = SpectrumQuality_Viewer.testNameID.PeakIntensity;
			stringTest = qsTr("{0} Test:".format(stringTestID));
			flagIntensityTestUsed = true;
			tabIndex = this.getTestTabIndex(this.dialog.widgets.tabWidget, stringTest);
			if (tabIndex === -1) {
				tabIndex = SpectrumQuality_Viewer.tabsIndexAndTestMapping.PeakIntensity;
			}

			if (this.dialog.widgets.tableWidgetPeakIntensity.rowCount > 0) {
				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakIntensity.tableWidget, this.peakIntensity.fromPPM, this.peakIntensity.checkBoxParameter, this.peakIntensity.numericConstraintForFromPPM);
					if (rowNumberWithFieldNotFilled > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the from ppm field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagIntensityTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakIntensity.tableWidget, this.peakIntensity.fromPPM, this.peakIntensity.checkBoxParameter);
					if (rowNumberWithNotNumberValue > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} the from ppm field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
						result = true;
						flagIntensityTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakIntensity.tableWidget, this.peakIntensity.toPPM, this.peakIntensity.checkBoxParameter, this.peakIntensity.numericConstraintForToPPM);
					if (rowNumberWithFieldNotFilled > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the to ppm field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagIntensityTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakIntensity.tableWidget, this.peakIntensity.toPPM, this.peakIntensity.checkBoxParameter);
					if (rowNumberWithNotNumberValue > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} the to ppm field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
						result = true;
						flagIntensityTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakIntensity.tableWidget, this.peakIntensity.peakType, this.peakIntensity.checkBoxParameter, this.peakIntensity.numericConstraintForPeakType);
					if (rowNumberWithFieldNotFilled > 0) {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the peak type field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagIntensityTestUsed = false;
					}
				}

				if (!result) {
					rowNumberWithFieldNotFilled = SpectrumQuality_Viewer.fieldIsFilled(this.peakIntensity.tableWidget, this.peakIntensity.valueParameter, this.peakIntensity.checkBoxParameter, this.peakIntensity.numericConstraintForValueParameter, this.peakIntensity.conditionParameter);
					if (rowNumberWithFieldNotFilled <= 0) {
						rowNumberWithNotNumberValue = SpectrumQuality_Viewer.fieldIsNumber(this.peakIntensity.tableWidget, this.peakIntensity.valueParameter, this.peakIntensity.checkBoxParameter);
						if (rowNumberWithNotNumberValue > 0) {
							this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
							MessageBox.critical(qsTr("{0} the intensity value field must be a number for row #{1}".format(stringTest, rowNumberWithNotNumberValue)));
							result = true;
							flagIntensityTestUsed = false;
						}
					} else {
						this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
						MessageBox.critical(qsTr("{0} a value is needed in the intensity value field for row #{1}".format(stringTest, rowNumberWithFieldNotFilled)));
						result = true;
						flagPeakWidthTestUsed = false;
					}
				}

				if (!result && SpectrumQuality_Viewer.getTotalRowsChecked(this.peakIntensity.tableWidget, this.peakIntensity.checkBoxParameter) === 0) {
					flagIntensityTestUsed = false;
				}
			} else {
				this.showTabIndex(this.dialog.widgets.tabWidget, tabIndex);
				MessageBox.critical(qsTr("{0} a row is needed".format(stringTest)));
				this.dialog.widgets.tableWidgetPeakIntensity.setFocus();
				result = true;
				flagIntensityTestUsed = false;
			}
		}

		//Purity filter checking
		if (this.dialog.widgets.gbPurity.checked) {
			flagPurityTestUsed = true;
		}

		//Digital Resolution filter checking
		if (this.dialog.widgets.gbDigitalResolution.checked) {
			flagDigitalResolutionTestUsed = true;
		}

		//Check if it has been set at least an option
		if (!result) {
			if (!flagAcquisitionParametersTestUsed) {
				if (!flagProcessingParametersTestUsed) {
					if (!flagSNRTestUsed) {
						if (!flagPhaseTestUsed) {
							if (!flagPeakWidthTestUsed) {
								if (!flagIntensityTestUsed) {
									if (!flagPurityTestUsed) {
										if (!flagDigitalResolutionTestUsed) {
											MessageBox.critical(qsTr("An option is needed to launch the script"));
											result = true;
										}
									}
								}
							}
						}
					}
				}
			}
		}

		return result;
	};


	SpectrumQuality_Viewer.prototype.generateHTMLReport = function (aTextReport) {

		var i, j, regex, regexResults, startPositions, htmlReport, start, end, stringText,
			auxStringText, stringArray, string, summaryLine, startSummaryLine, summaryLinePosition,
			newSummaryLine, excludeWordsObject, excludeWords, auxNewTempWord, resultsViewerOptionsDialog,
			useSettings, fontSize, fontColor, fontType, textHighlight, textHighlightColor, keywordsToFindDynamicLinesInHeader,
			occurencesOfkeywordsToFindDynamicLinesInHeader;

		//Get options related to viewer options with settings already loaded
		resultsViewerOptionsDialog = SpectrumQuality_Viewer.getResultsViewerOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityResultsViewerSettings.ui');

		//Get settings shortcut
		useSettings = resultsViewerOptionsDialog.widgets.gbRichText.checked;
		fontSize = resultsViewerOptionsDialog.widgets.sbFontSize.value;
		fontColor = resultsViewerOptionsDialog.widgets.colorComboBox.currentText;
		fontType = resultsViewerOptionsDialog.widgets.fontComboBox.currentText;
		textHighlight = resultsViewerOptionsDialog.widgets.cbTextHighlight.checked;

		//It manage some words which will be excluded for regexp expression in the report
		//First value means the expression to be excluded, second one is the new temp expression
		//The tast term here is not a typo, it was intended.
		excludeWordsObject = {};
		excludeWordsObject["asymmetry test"] = "asymmetry tast";

		//It performs a temp replacement of the words above
		for (excludeWords in excludeWordsObject) {
			if (excludeWordsObject.hasOwnProperty(excludeWords)) {
				auxNewTempWord = excludeWordsObject[excludeWords];
				aTextReport = aTextReport.replace(new RegExp(excludeWords, "g"), auxNewTempWord);
			}
		}

		/*jslint regexp: true*/
		regex = /\[(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?:.*/g;
		/*jslint regexp: false*/

		//Initialize vars
		startPositions = [];
		string = aTextReport;
		summaryLinePosition = 2;

		//Check for dynamic lines in the header. This lines may or not appear depending on the options used
		//Each line matched will increase the summaryLinPosition counter
		keywordsToFindDynamicLinesInHeader = new RegExp(SpectrumQuality_Viewer.generalOptions.KeepCurrentData + "|" + SpectrumQuality_Viewer.generalOptions.UseCurrentAnalysis, "g");
		occurencesOfkeywordsToFindDynamicLinesInHeader = string.match(keywordsToFindDynamicLinesInHeader);
		if (occurencesOfkeywordsToFindDynamicLinesInHeader !== null) {
			if (occurencesOfkeywordsToFindDynamicLinesInHeader !== undefined) {
				if (occurencesOfkeywordsToFindDynamicLinesInHeader.length !== undefined) {
					if (!isNaN(occurencesOfkeywordsToFindDynamicLinesInHeader.length)) {
						summaryLinePosition += occurencesOfkeywordsToFindDynamicLinesInHeader.length;
					}
				}
			}
		}

		//Get the array with the index of the string
		do {
			regexResults = regex.exec(string);
			if (regexResults) {
				startPositions.push(regexResults.index);
			}
		} while (regexResults);

		//Generate first row
		htmlReport = '<table>';
		if (startPositions.length > 0 && startPositions[0] > 0) {
			if (useSettings) {
				htmlReport += "<tr><td><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + string.substring(0, startPositions[0]) + "</font></td></tr>";
			} else {
				htmlReport += '<tr><td>' + string.substring(0, startPositions[0]) + '</td></tr>';
			}
		}

		//Compose HTML Report
		for (i = 0; i < startPositions.length; i++) {
			if (startPositions.length === 1) {
				start = startPositions[i];
				end = start;
				auxStringText = string.substring(end, string.length);
				stringArray = auxStringText.split("\n");
				for (j = 0; j < stringArray.length; j++) {
					end += stringArray[j].length + 1;
				}
				stringText = string.substring(start, end);
			} else {
				if (i < startPositions.length - 1) {
					start = startPositions[i];
					end = startPositions[i + 1];
					stringText = string.substring(start, end);
				} else {
					start = end;
					auxStringText = string.substring(end, string.length);
					stringArray = auxStringText.split("\n");
					for (j = 0; j < stringArray.length; j++) {
						end += stringArray[j].length + 1;
					}
					stringText = string.substring(start, end);
				}
			}

			//Replace problematic tokens
			auxStringText = stringText;
			stringText = Str.specialCharactersToXMLEntities(auxStringText);

			//It prints the first line of each block in bold type
			stringArray = stringText.split("\n");
			stringText = "";
			for (j = 0; j < stringArray.length; j++) {

				//Bold control
				/*jslint regexp: true*/
				if (stringArray[j].match(/(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?: .*/g)) {
					if (useSettings) {
						stringText += "<font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringArray[j] + "</font>";
					} else {
						stringText += '<font style=\"font-weight:bold\">' + stringArray[j] + '</font>';
					}
				} else {
					if (useSettings) {
						stringText += "<font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringArray[j] + "</font>";
					} else {
						stringText += stringArray[j];
					}
				}
				/*jslint regexp: false*/

				//Add the new line token only if is not the last iteration
				if (j !== (stringArray.length - 1)) {
					stringText += "\n";
				}
			}

			//We paint each row depending on the result type
			/*jslint regexp: true*/
			if (stringText.match(/(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?: FAILED.*/g)) {
				if (textHighlight) {
					textHighlightColor = " bgcolor = #FFB3B3";
				}
				if (useSettings) {
					htmlReport += "<tr><td" + textHighlightColor + "><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringText + "</font></td></tr>";
				} else {
					htmlReport += "<tr><td bgcolor = #FFB3B3><font color = darkRed>" + stringText + "</font></td></tr>";
				}
			} else if (stringText.match(/(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?: PASSED.*/g)) {
				if (textHighlight) {
					textHighlightColor = " bgcolor = #B3FFB3";
				}
				if (useSettings) {
					htmlReport += "<tr><td" + textHighlightColor + "><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringText + "</font></td></tr>";
				} else {
					htmlReport += "<tr><td bgcolor = #B3FFB3><font color = dargGreen>" + stringText + "</font></td></tr>";
				}
			} else if (stringText.match(/(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?: PERFORMED.*/g)) {
				if (textHighlight) {
					textHighlightColor = " bgcolor = #B3B3FF";
				}
				if (useSettings) {
					htmlReport += "<tr><td" + textHighlightColor + "><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringText + "</font></td></tr>";
				} else {
					htmlReport += "<tr><td bgcolor = #B3B3FF><font color = darkBlue>" + stringText + "</font></td></tr>";
				}
			} else if (stringText.match(/(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?: UNTESTED.*/g)) {
				if (textHighlight) {
					textHighlightColor = " bgcolor = #FFBE00";
				}
				if (useSettings) {
					htmlReport += "<tr><td" + textHighlightColor + "><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringText + "</font></td></tr>";
				} else {
					htmlReport += "<tr><td bgcolor = #FFBE00><font color = dargYellow>" + stringText + "</font></td></tr>";
				}
			} else if (stringText.match(/(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?: NOT PERFORMED.*/g)) {
				if (textHighlight) {
					textHighlightColor = " bgcolor = #FFA660";
				}
				if (useSettings) {
					htmlReport += "<tr><td" + textHighlightColor + "><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringText + "</font></td></tr>";
				} else {
					htmlReport += "<tr><td bgcolor = #FFA660><font color = #AF2010>" + stringText + "</font></td></tr>";
				}
			} else if (stringText.match(/(INFO|WARNING|ERROR).*test(\s#\d.*)?(\(s\))?: NOT_USED.*/g)) {
				if (textHighlight) {
					textHighlightColor = " bgcolor = #F0F0F0";
				}
				if (useSettings) {
					htmlReport += "<tr><td" + textHighlightColor + "><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringText + "</font></td></tr>";
				} else {
					htmlReport += "<tr><td bgcolor = #F0F0F0>" + stringText + "</td></tr>";
				}
			} else {
				if (useSettings) {
					htmlReport += "<tr><td><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + stringText + "</font></td></tr>";
				} else {
					htmlReport += "<tr><td>" + stringText + "</td></tr>";
				}
			}
			/*jslint regexp: false*/
		}

		htmlReport += '</table>';

		//Remove tabs in order to drop the left alignment
		htmlReport = htmlReport.replace(/\t/g, "");

		//Adapt ASCII symbols to HTML code
		htmlReport = htmlReport.replace(/\n/g, "<br>");

		//We print bold the summary line
		stringArray = htmlReport.split("<br>");
		if (stringArray.length > (summaryLinePosition + 1) && stringArray[(summaryLinePosition + 1)].trim().length > 2) {
			summaryLine = stringArray[summaryLinePosition];
			startSummaryLine = htmlReport.indexOf(summaryLine);
			if (useSettings) {
				newSummaryLine = "<font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\"><br>" + summaryLine + "</font>";
			} else {
				newSummaryLine = "<font style=\"font-weight:bold\"><br>" + summaryLine + "</font>";
			}
			newSummaryLine += "<br><br>--------------- DETAILED INFORMATION ---------------";
			htmlReport = htmlReport.replace(summaryLine, newSummaryLine);
		} else {
			htmlReport = "<table><tr><td>";
			htmlReport += aTextReport.replace(/\n/g, "<br>");
			htmlReport += "</td></tr></table>";
		}

		//Finally it reverts the regexp exclude words to its normal value
		for (excludeWords in excludeWordsObject) {
			if (excludeWordsObject.hasOwnProperty(excludeWords)) {
				auxNewTempWord = excludeWordsObject[excludeWords];
				htmlReport = htmlReport.replace(new RegExp(auxNewTempWord, "g"), excludeWords);
			}
		}

		return htmlReport;
	};

	SpectrumQuality_Viewer.prototype.executeSQA = function (aSpectra, aParameters) {

		var spectra, spectrum, total1DSpectra, spectra2D, total2DSpectra, flagProcess,
			results, separatorString, useSettings, fontSize, fontType, fontColor,
			textHighlight, resultsViewerOptionsSettings;

		//Initialize vars
		spectra = [];
		spectra2D = [];
		total1DSpectra = 0;
		total2DSpectra = 0;

		//Get spectra from document
		if (aSpectra === undefined) {
			spectra = SpectrumQuality_Viewer.getSelectedSpectra(1);
			total1DSpectra = spectra.length;
			spectra2D = SpectrumQuality_Viewer.getSelectedSpectra(2);
			total2DSpectra = spectra2D.length;

			//If no page selection it uses the active spectrum instead
			if (spectra.length === 0 && spectra2D.length === 0) {
				spectrum = nmr.activeSpectrum();
				if (spectrum !== undefined && spectrum.uuid !== undefined && spectrum.isValid()) {
					if (spectrum.dimCount === 1) {
						spectra.push(spectrum);
						total1DSpectra = 1;
					} else if (spectrum.dimCount === 2) {
						spectra2D.push(spectrum);
						total2DSpectra = 1;
					}
				}
			}

		} else {

			//Get spectra from parameter
			if (aSpectra.length > 0) {
				for (i = 0; i < aSpectra.length; i++) {
					spectrum = aSpectra[i];
					if (spectrum.name === "NMR Spectrum") {
						if (spectrum.dimCount === 1) {
							spectra.push(spectrum);
							total1DSpectra++;
						} else if (spectrum.dimCount === 2) {
							spectra.push(spectrum);
							total2DSpectra++;
						}
					}
				}

			} else if (aSpectra.name === "NMR Spectrum") {
				if (aSpectra.dimCount === 1) {
					spectra.push(aSpectra);
					total1DSpectra++;
				} else if (aSpectra.dimCount === 2) {
					spectra2D.push(aSpectra);
					total2DSpectra++;
				}
			}
		}

		//Create an engine instance
		if (aParameters === undefined) {
			engine = new SpectrumQuality_Engine();
		} else {
			engine = new SpectrumQuality_Engine(aParameters);
		}

		//Check if there are only 2D spectra selected
		if (total1DSpectra === 0 && total2DSpectra > 0) {
			MessageBox.critical(qsTr("Dataset is not compatible with the Spectrum Quality analysis. The selection must contain a 1D spectrum."));

			//At least there is a 1D selected spectrum
		} else if (total1DSpectra > 0) {

			//Initialize flag
			flagProcess = true;

			//Check if there are mixed 1D and 2D selected spectra
			if (total2DSpectra > 0) {
				dialogAnswer = MessageBox.warning(qsTr("There are some 2D spectra in the selection. They will not be processed. Do you want to continue?"), MessageBox.Ok, MessageBox.Cancel, "");
				if (dialogAnswer ===  MessageBox.Cancel) {
					flagProcess = false;
				}
			}

			//We process only if is needed
			if (flagProcess) {
				if (Application.spectrumQualityResultViewer === undefined) {
					Application.spectrumQualityResultViewer = Application.loadUiFile('ricares:SpectrumQualityResultsViewer.ui');
					flagFirstTime = true;
				} else {
					flagFirstTime = false;
				}
				Application.spectrumQualityResultViewer.cancel = false;
				Application.spectrumQualityResultViewer.show();
				Application.spectrumQualityResultViewer.widgets.btFinish.clicked.connect(Application.spectrumQualityResultViewer, function () { Application.spectrumQualityResultViewer.cancel = true; });
				Application.spectrumQualityResultViewer.widgets.progressBar.setVisible(true);
				Application.spectrumQualityResultViewer.widgets.btFinish.setVisible(true);
				Application.spectrumQualityResultViewer.widgets.progressBar.value = 0;
				Application.spectrumQualityResultViewer.widgets.teLog.html = "";
				Application.spectrumQualityResultViewer.lastTextReport = [];

				//Get options related to viewer options with settings already loaded
				resultsViewerOptionsSettings = SpectrumQuality_Viewer.getResultsViewerOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityResultsViewerSettings.ui');

				//Get settings shortcut
				useSettings = resultsViewerOptionsSettings.widgets.gbRichText.checked;
				fontSize = resultsViewerOptionsSettings.widgets.sbFontSize.value;
				fontColor = resultsViewerOptionsSettings.widgets.colorComboBox.currentText;
				fontType = resultsViewerOptionsSettings.widgets.fontComboBox.currentText;
				textHighlight = resultsViewerOptionsSettings.widgets.cbTextHighlight.checked;

				//Call to engine spectrum by spectrum
				for (i = 0; i < total1DSpectra && !Application.spectrumQualityResultViewer.cancel; i++) {

					if (i === 0) {
						Application.spectrumQualityResultViewer.widgets.btFinish.setVisible(true);
						Application.spectrumQualityResultViewer.widgets.progressBar.setVisible(true);
					}

					results = engine.process(spectra[i]);
					Application.spectrumQualityResultViewer.widgets.progressBar.value = ((i + 1) / (total1DSpectra)) * 100;
					Application.spectrumQualityResultViewer.widgets.progressBar.update();
					Application.spectrumQualityResultViewer.lastTextReport.push(results.log);
					htmlReport = this.generateHTMLReport(results.log);
					Application.spectrumQualityResultViewer.widgets.teLog.html += htmlReport;
					mainWindow.processEvents();
					if (i !== total1DSpectra - 1) {
						if (useSettings !== undefined && useSettings) {
							separatorString = "<br><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + SpectrumQuality_Viewer.separatorSymbol + "</font><br>";
						} else {
							separatorString = "<br>" + SpectrumQuality_Viewer.separatorSymbol + "<br>";
						}
						Application.spectrumQualityResultViewer.widgets.teLog.html += separatorString;
					}
				}

				Application.spectrumQualityResultViewer.widgets.progressBar.value = 100;
				Application.spectrumQualityResultViewer.widgets.btFinish.setVisible(false);
				Application.spectrumQualityResultViewer.widgets.progressBar.setVisible(false);

				Application.spectrumQualityResultViewer.resultsObject = {};
				Application.spectrumQualityResultViewer.resultsObject.filePathKey = SpectrumQuality_Viewer.resultsFilePathKey;
				Application.spectrumQualityResultViewer.resultsObject.resultsString = Application.spectrumQualityResultViewer.widgets.teLog.plainText;
				SpectrumQuality_Viewer.htmlResults = Application.spectrumQualityResultViewer.widgets.teLog.html;

				if (mainWindow.activeDocument !== undefined) {
					Application.spectrumQualityResultViewer.resultsObject.page = mainWindow.activeDocument.curPage();
				}

				if (flagFirstTime) {
					Application.spectrumQualityResultViewer.widgets.btCopyToDocument.enabled = true;
					Application.spectrumQualityResultViewer.widgets.btCopyToDocument.clicked.connect(SpectrumQuality_Viewer.copyResultsToCurrentPage);
					Application.spectrumQualityResultViewer.widgets.btSaveToFile.enabled = true;
					Application.spectrumQualityResultViewer.widgets.btSaveToFile.clicked.connect(SpectrumQuality_Viewer.saveResults);
					Application.spectrumQualityResultViewer.widgets.btSettings.clicked.connect(this, SpectrumQuality_Viewer.launchViewerSettings);
				}
			}
		}

		//Save values to registry
		if (flagProcess) {
			this.saveValuesToRegistry();
		}

		//Return the results thrown by the engine
		return results;
	};

	SpectrumQuality_Viewer.prototype.loadResult = function (aEngineResultObject) {

		var results, htmlReport, flagFirstTime;

		if (aEngineResultObject !== undefined && aEngineResultObject.log !== undefined && aEngineResultObject.log !== "") {
			results = aEngineResultObject;
			if (Application.spectrumQualityResultViewer === undefined) {
				Application.spectrumQualityResultViewer = Application.loadUiFile('ricares:SpectrumQualityResultsViewer.ui');
				flagFirstTime = true;
			} else {
				flagFirstTime = false;
			}

			//Initialize vars
			Application.spectrumQualityResultViewer.cancel = false;
			Application.spectrumQualityResultViewer.lastTextReport = [];
			Application.spectrumQualityResultViewer.show();
			Application.spectrumQualityResultViewer.widgets.progressBar.setVisible(true);
			Application.spectrumQualityResultViewer.widgets.btFinish.setVisible(true);
			Application.spectrumQualityResultViewer.widgets.progressBar.value = 0;
			Application.spectrumQualityResultViewer.widgets.teLog.html = "";
			Application.spectrumQualityResultViewer.widgets.btFinish.clicked.connect(Application.spectrumQualityResultViewer, function () { Application.spectrumQualityResultViewer.cancel = true; });

			//Write report
			Application.spectrumQualityResultViewer.widgets.progressBar.update();
			htmlReport = this.generateHTMLReport(results.log);
			Application.spectrumQualityResultViewer.lastTextReport.push(results.log);
			Application.spectrumQualityResultViewer.widgets.teLog.html = htmlReport;
			mainWindow.processEvents();

			//Hide progress bar
			Application.spectrumQualityResultViewer.widgets.progressBar.value = 100;
			Application.spectrumQualityResultViewer.widgets.btFinish.setVisible(false);
			Application.spectrumQualityResultViewer.widgets.progressBar.setVisible(false);

			Application.spectrumQualityResultViewer.resultsObject = {};
			Application.spectrumQualityResultViewer.resultsObject.filePathKey = SpectrumQuality_Viewer.resultsFilePathKey;
			Application.spectrumQualityResultViewer.resultsObject.resultsString = Application.spectrumQualityResultViewer.widgets.teLog.plainText;
			SpectrumQuality_Viewer.htmlResults = Application.spectrumQualityResultViewer.widgets.teLog.html;

			if (mainWindow.activeDocument !== undefined) {
				Application.spectrumQualityResultViewer.resultsObject.page = mainWindow.activeDocument.curPage();
			}

			if (flagFirstTime) {
				Application.spectrumQualityResultViewer.widgets.btCopyToDocument.enabled = true;
				Application.spectrumQualityResultViewer.widgets.btCopyToDocument.clicked.connect(SpectrumQuality_Viewer.copyResultsToCurrentPage);
				Application.spectrumQualityResultViewer.widgets.btSaveToFile.enabled = true;
				Application.spectrumQualityResultViewer.widgets.btSaveToFile.clicked.connect(SpectrumQuality_Viewer.saveResults);
				Application.spectrumQualityResultViewer.widgets.btSettings.clicked.connect(this, SpectrumQuality_Viewer.launchViewerSettings);
			}
		}
	};

	SpectrumQuality_Viewer.prototype.loadGUI = function () {

		var  showDialog, parameters, results;

		this.loadWidget();

		//The exec() print windows. This means we need to have already loaded the previous signal which manage events thanks to connected method.
		showDialog = true;
		while (showDialog) {

			//Check if cancel button is pulsed by the user
			if (!this.dialog.exec()) {
				return;
			}

			if (this.validateGUIParameters()) {
				continue;
			}

			showDialog = false;
		}

		//Generate Settings Mode (without execution)
		if (aSettingsMode !== undefined && aSettingsMode === true) {
			this.generateSettings();

		//Normal Mode (with execution)
		} else {

			//Prepare parameters to the engine
			parameters = {};

			//Get general settings values
			generalSettingsDialog = SpectrumQuality_Viewer.getGeneralOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityGeneralSettings.ui');
			if (generalSettingsDialog !== undefined) {
				if (generalSettingsDialog.widgets !== undefined) {
					parameters.keepCurrentData = generalSettingsDialog.widgets.cbKeepCurrentData.checked;
					parameters.useCurrentAnalysis = generalSettingsDialog.widgets.cbUseCurrentAnalysis.checked;
				}
			}

			//Prepare parameters related to the main dialog
			parameters.acquisitionParameters = SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetAcquisitionParameters.items, this.acquisitionParameter.checkBoxParameter, this.acquisitionParameter.parameterParameter, this.acquisitionParameter.conditionParameter, this.acquisitionParameter.valueParameter);
			parameters.processingParameters = SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetProcessingParameters.items, this.processingParameter.checkBoxParameter, this.processingParameter.parameterParameter, this.processingParameter.conditionParameter, this.processingParameter.valueParameter);
			parameters.signalToNoiseFilterStatus = this.dialog.widgets.gbSignalToNoise.checked;
			parameters.signalFullSpectrum = this.dialog.widgets.rbSignalFullSpectrum.checked;
			parameters.signalFrom = this.dialog.widgets.leFromSignal.text;
			parameters.signalTo = this.dialog.widgets.leToSignal.text;
			parameters.noiseAutomatic = this.dialog.widgets.rbAutomaticNoise.checked;
			parameters.noiseFrom = this.dialog.widgets.leFromNoise.text;
			parameters.noiseTo = this.dialog.widgets.leToNoise.text;
			parameters.snrMinValue = this.dialog.widgets.leSignalNoiseMinimumValue.text;
			parameters.phaseErrorFilterStatus = this.dialog.widgets.gbPhase.checked;
			parameters.phaseErrorCondition = SpectrumQuality_Engine.phaseErrorCondition;
			parameters.phaseErrorValue = this.dialog.widgets.spbxPhaseValue.value;
			parameters.peakFilterStatus = this.dialog.widgets.gbPeakWidth.checked;
			parameters.peakWidthParameters = SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetPeakWidth.items, this.peakWidth.checkBoxParameter, this.peakWidth, this.peakWidth.conditionParameter, this.peakWidth.valueParameter);
			parameters.peakWidthDecimals = 4;
			parameters.peakWidthFullSpectrum = false;
			if (parameters.peakFilterStatus && this.dialog.widgets.tableWidgetPeakWidth.rowCount === 0) {
				parameters.peakFilterStatus = false;
			}
			parameters.peakIntensityFilterStatus = this.dialog.widgets.gbPeakIntensity.checked;
			parameters.peakIntensityParameters = SpectrumQuality_Viewer.getDataFromTableWidget(this.dialog.widgets.tableWidgetPeakIntensity.items, this.peakIntensity.checkBoxParameter, this.peakIntensity, this.peakIntensity.conditionParameter, this.peakIntensity.valueParameter);
			parameters.peakIntensityDecimals = 4;
			parameters.peakIntensityFullSpectrum = false;
			if (parameters.peakIntensityFilterStatus && this.dialog.widgets.tableWidgetPeakIntensity.rowCount === 0) {
				parameters.peakIntensityFilterStatus = false;
			}
			parameters.purityFilterStatus = this.dialog.widgets.gbPurity.checked;
			parameters.purityCondition = SpectrumQuality_Engine.purityCondition;
			parameters.purityValue = this.dialog.widgets.spbxPurityValue.value;
			parameters.digitalResolutionFilterStatus = this.dialog.widgets.gbDigitalResolution.checked;
			parameters.digitalResolutionCondition = SpectrumQuality_Engine.digitalResolutionCondition;
			parameters.digitalResolutionValue = this.dialog.widgets.spbxDigitalResolutionValue.value;

			results = this.executeSQA(undefined, parameters);

			return results;
		}
	};


	//-----------------------MAIN PROGRAM OF VIWER CLASS---------------------------//
	if (flagExit) {
		return;
	}

	//-----------------------SIGNALS---------------------------
	//Manage setting buttons
	this.dialog.widgets.tbLoadSettings.clicked.connect(this, this.loadSettings);
	this.dialog.widgets.tbSaveSettings.clicked.connect(this, this.saveSettings);
	this.dialog.widgets.tbSettings.clicked.connect(this, SpectrumQuality_Viewer.launchSettings);

	//**********Acquisition Parameter TableView Signals**********
	//Prepare the object which will be sent
	this.acquisitionParameter.addParameters = this.addParameters;
	this.acquisitionParameter.loadParametersTable = this.loadParametersTable;
	this.acquisitionParameter.checkAllRows = this.checkAllRows;
	this.acquisitionParameter.uncheckAllRows = this.uncheckAllRows;

	//Active signal in order to know when a checkbox has been checked or unchecked
	this.dialog.widgets.tableWidgetAcquisitionParameters.cellChanged.connect(this.acquisitionParameter, SpectrumQuality_Viewer.cellRowsChanged);

	//Active signal in order to know when a cell has been clicked
	this.dialog.widgets.tableWidgetAcquisitionParameters.cellDoubleClicked.connect(this.acquisitionParameter, SpectrumQuality_Viewer.setConditionAndPeakType);

	//Active signal to detect the selected table items in order to allow to the user delete them
	this.dialog.widgets.tableWidgetAcquisitionParameters.itemSelectionChanged.connect(this.acquisitionParameter, this.selectionChanged);

	//Manage Add Row Button Signal
	this.dialog.widgets.tbAddAcquisitionParameters.clicked.connect(this.acquisitionParameter, this.addRow);

	//Manage Remove Row Button Signal
	this.dialog.widgets.tbDeleteAcquisitionParameters.clicked.connect(this.acquisitionParameter, this.deleteRows);

	//Manage Check all Button Signal
	this.dialog.widgets.tbCheckAllAcquisitionParameters.clicked.connect(this.acquisitionParameter, this.checkAllRows);

	//Manage Uncheck all Button Signal
	this.dialog.widgets.tbUncheckAllAcquisitionParameters.clicked.connect(this.acquisitionParameter, this.uncheckAllRows);

	//**********Processing Parameter TableView Signals**********
	//Prepare the object which will be sent
	this.processingParameter.addParameters = this.addParameters;
	this.processingParameter.loadParametersTable = this.loadParametersTable;
	this.processingParameter.checkAllRows = this.checkAllRows;
	this.processingParameter.uncheckAllRows = this.uncheckAllRows;
	this.processingParameter.getProcessingParameters = this.getProcessingParameters;

	//Active signal in order to know when a checkbox has been checked or unchecked
	this.dialog.widgets.tableWidgetProcessingParameters.cellChanged.connect(this.processingParameter, SpectrumQuality_Viewer.cellRowsChanged);

	//Active signal in order to know when a cell has been double clicked
	this.dialog.widgets.tableWidgetProcessingParameters.cellDoubleClicked.connect(this.processingParameter, SpectrumQuality_Viewer.setConditionAndPeakType);

	//Active signal to detect the selected table items in order to allow to the user delete them
	this.dialog.widgets.tableWidgetProcessingParameters.itemSelectionChanged.connect(this.processingParameter, this.selectionChanged);

	//Manage Add Row Button Signal
	this.dialog.widgets.tbAddProcessingParameters.clicked.connect(this.processingParameter, this.addRow);

	//Manage Remove Row Button Signal
	this.dialog.widgets.tbDeleteProcessingParameters.clicked.connect(this.processingParameter, this.deleteRows);

	//Manage Check all Button Signal
	this.dialog.widgets.tbCheckAllProcessingParameters.clicked.connect(this.processingParameter, this.checkAllRows);

	//Manage Uncheck all Button Signal
	this.dialog.widgets.tbUncheckAllProcessingParameters.clicked.connect(this.processingParameter, this.uncheckAllRows);

	//**********Peak Width TableView Signals**********
	//Prepare the object which will be sent
	this.peakWidth.addParameters = this.addParameters;
	this.peakWidth.loadParametersTable = this.loadParametersTable;
	this.peakWidth.checkAllRows = this.checkAllRows;
	this.peakWidth.uncheckAllRows = this.uncheckAllRows;
	this.peakWidth.getPeakWidths = this.getPeakWidths;

	//Active signal in order to know when a checkbox has been checked or unchecked
	this.dialog.widgets.tableWidgetPeakWidth.cellChanged.connect(this.peakWidth, SpectrumQuality_Viewer.cellRowsChanged);

	//Active signal in order to know when a cell has been double clicked
	this.dialog.widgets.tableWidgetPeakWidth.cellDoubleClicked.connect(this.peakWidth, SpectrumQuality_Viewer.setConditionAndPeakType);

	//Active signal to detect the selected table items in order to allow to the user delete them
	this.dialog.widgets.tableWidgetPeakWidth.itemSelectionChanged.connect(this.peakWidth, this.selectionChanged);

	//Manage Add Row Button Signal
	this.dialog.widgets.tbAddPeakWidth.clicked.connect(this.peakWidth, this.addRow);

	//Manage Remove Row Button Signal
	this.dialog.widgets.tbDeletePeakWidth.clicked.connect(this.peakWidth, this.deleteRows);

	//Manage Check all Button Signal
	this.dialog.widgets.tbCheckAllPeakWidth.clicked.connect(this.peakWidth, this.checkAllRows);

	//Manage Uncheck all Button Signal
	this.dialog.widgets.tbUncheckAllPeakWidth.clicked.connect(this.peakWidth, this.uncheckAllRows);

	//**********Peak Intensity TableView Signals**********
	//Prepare the object which will be sent
	this.peakIntensity.addParameters = this.addParameters;
	this.peakIntensity.loadParametersTable = this.loadParametersTable;
	this.peakIntensity.checkAllRows = this.checkAllRows;
	this.peakIntensity.uncheckAllRows = this.uncheckAllRows;
	this.peakIntensity.getIntensity = this.getIntensity;

	//Active signal in order to know when a checkbox has been checked or unchecked
	this.dialog.widgets.tableWidgetPeakIntensity.cellChanged.connect(this.peakIntensity, SpectrumQuality_Viewer.cellRowsChanged);

	//Active signal in order to know when a cell has been double clicked
	this.dialog.widgets.tableWidgetPeakIntensity.cellDoubleClicked.connect(this.peakIntensity, SpectrumQuality_Viewer.setConditionAndPeakType);

	//Active signal to detect the selected table items in order to allow to the user delete them
	this.dialog.widgets.tableWidgetPeakIntensity.itemSelectionChanged.connect(this.peakIntensity, this.selectionChanged);

	//Manage Add Row Button Signal
	this.dialog.widgets.tbAddPeakIntensity.clicked.connect(this.peakIntensity, this.addRow);

	//Manage Remove Row Button Signal
	this.dialog.widgets.tbDeletePeakIntensity.clicked.connect(this.peakIntensity, this.deleteRows);

	//Manage Check all Button Signal
	this.dialog.widgets.tbCheckAllPeakIntensity.clicked.connect(this.peakIntensity, this.checkAllRows);

	//Manage Uncheck all Button Signal
	this.dialog.widgets.tbUncheckAllPeakIntensity.clicked.connect(this.peakIntensity, this.uncheckAllRows);

	//-------------------------MAIN PROGRAM---------------------------
	//Decide viability mode
	if (aSettingsMode !== undefined && aSettingsMode === true) {
		flagShowGuiIfErrors = true;
	} else {
		flagShowGuiIfErrors = false;
	}

	//Dialog must be shown when we have compatible data to be processed
	//According to the compatibility mode chosen by the aStandAloneMode parameter
	processingParameters = this.getProcessingParameters();
	if (flagShowGuiIfErrors) {
		results = this.loadGUI();
	} else {
		if (!flagShowGuiIfErrors && processingParameters !== undefined) {
			results = this.loadGUI();
		} else {
			MessageBox.critical(qsTr("Dataset is not compatible with the Spectrum Quality analysis. The selection must contain a 1D spectrum."));
		}
	}

	return results;

}


//------------------------------STATIC ATTRIBUTES-------------------------------------
SpectrumQuality_Viewer.lastTabIndexViewedKey = "Spectrum Quality/Last Tab Index Viewed";
SpectrumQuality_Viewer.keepCurrentDataKey = "Spectrum Quality/Keep Current Data";
SpectrumQuality_Viewer.useCurrentAnalysisKey = "Spectrum Quality/Use Current Analysis";
SpectrumQuality_Viewer.generalDataFileKey = "Spectrum Quality/Settings Folder";
SpectrumQuality_Viewer.resultsFilePathKey = "Spectrum Quality/Results File Path";
SpectrumQuality_Viewer.lastTabKey = "Spectrum Quality/Last Tab";
SpectrumQuality_Viewer.richTextFlagKey = "Spectrum Quality/Rich Text Flag";
SpectrumQuality_Viewer.typeFontKey = "Spectrum Quality/Type Font";
SpectrumQuality_Viewer.sizeFontKey = "Spectrum Quality/Size Font";
SpectrumQuality_Viewer.colorFontKey = "Spectrum Quality/Color Font";
SpectrumQuality_Viewer.useTestHightLightKey = "Spectrum Quality/Use Text Highlight";
SpectrumQuality_Viewer.separatorSymbol = "*********";
SpectrumQuality_Viewer.generalOptions = {
	KeepCurrentData: "Run Analysis in the Background",
	UseCurrentAnalysis: "Use Current Analysis if Present"
};
SpectrumQuality_Viewer.tabsIndexAndTestMapping = {
	AcquisitionParameters: 0,
	ProcessingParameters: 1,
	SignalToNoise: 2,
	Phase: 3,
	PeakWidth: 4,
	PeakIntensity: 5,
	Purity: 6,
	DigitalResolution: 7
};
SpectrumQuality_Viewer.testNameID = {
	AcquisitionParameters: "Acquisition Parameters",
	ProcessingParameters: "Processing Parameters",
	SignalToNoise: "Signal-To-Noise",
	Phase: "Phase",
	PeakWidth: "Peak Width",
	PeakIntensity: "Peak Intensity",
	Purity: "Purity",
	DigitalResolution: "Digital Resolution"
};

//------------------------------STATIC METHODS-------------------------------------
SpectrumQuality_Viewer.cellRowsChanged = function (row, col) {
	"use strict";

	var items;

	if (col === 0) {

		this.tbCheckAll.enabled = false;
		this.tbUncheckAll.enabled = false;

		items = this.tableWidget.items;
		if (items[row][this.checkBoxParameter].checkState === 2) {
			this.totalRowsChecked++;
			if (this.totalRowsLoaded !== undefined && this.totalRowsLoaded !== -1) {
				this.totalRowsLoaded++;
			}
		} else if (this.totalRowsLoaded === undefined || (this.totalRowsLoaded === -1 && (items[row][this.checkBoxParameter].checkState === 0))) {
			this.totalRowsChecked--;
		}
		if (this.totalRowsChecked < this.tableWidget.rowCount) {
			this.tbCheckAll.enabled = true;
		}
		if (this.totalRowsChecked > 0) {
			this.tbUncheckAll.enabled = true;
		}

		this.tableWidget.resizeColumnToContents(col);
	}
};

SpectrumQuality_Viewer.getCondition = function () {
	"use strict";

	var dialog, showDialog, canceled, result;

	dialog = Application.loadUiFile('ricares:SpectrumQualityAddConditions.ui');
	showDialog = true;
	canceled = false;
	while (showDialog) {
		//Check if cancel button is pulsed by user
		if (!dialog.exec()) {
			canceled = true;
			showDialog = false;
		}
		showDialog = false;
	}

	if (!canceled) {
		result = dialog.widgets.cbCondition.currentText;
	}

	return result;
};

SpectrumQuality_Viewer.getDataFromTableWidget = function (aTableWidgetItems, aCheckedColumnNumber, aParameterColumnNumber, aConditionColumnNumber, aValueColumnNumber) {
	"use strict";

	var i, items, result;

	items = aTableWidgetItems;
	result = {};
	for (i = 0; i < items.length; i++) {
		result[i] = {};
		if (items[i][aCheckedColumnNumber].checkState === 2) {
			result[i].checked = true;
		} else {
			result[i].checked = false;
		}
		if ((typeof (aParameterColumnNumber) === "object")) {
			if (items[i][aParameterColumnNumber.fromPPM] !== undefined) {
				if (items[i][aParameterColumnNumber.fromPPM].text !== undefined) {
					result[i].fromPPM = items[i][aParameterColumnNumber.fromPPM].text;
				}
			}
			if (items[i][aParameterColumnNumber.toPPM] !== undefined) {
				if (items[i][aParameterColumnNumber.toPPM].text !== undefined) {
					result[i].toPPM = items[i][aParameterColumnNumber.toPPM].text;
				}
			}
			if (items[i][aParameterColumnNumber.peakType] !== undefined) {
				if (items[i][aParameterColumnNumber.peakType].text !== undefined) {
					result[i].peakType = items[i][aParameterColumnNumber.peakType].text;
				}
			}
			if (items[i][aParameterColumnNumber.atHeight] !== undefined) {
				if (items[i][aParameterColumnNumber.atHeight].text !== undefined) {
					result[i].atHeight = items[i][aParameterColumnNumber.atHeight].text;
				}
			}
			if (items[i][aParameterColumnNumber.asymmetryConditionParameter] !== undefined) {
				if (items[i][aParameterColumnNumber.asymmetryConditionParameter].text !== undefined) {
					result[i].asymmetryConditionParameter = items[i][aParameterColumnNumber.asymmetryConditionParameter].text;
				}
			}
			if (items[i][aParameterColumnNumber.asymmetryValueParameter]) {
				if (items[i][aParameterColumnNumber.asymmetryValueParameter].text !== undefined) {
					result[i].asymmetryValueParameter = items[i][aParameterColumnNumber.asymmetryValueParameter].text;
				}
			}
		} else if (items[i][aParameterColumnNumber] !== undefined) {
			if (items[i][aParameterColumnNumber].text !== undefined) {
				result[i].parameter = items[i][aParameterColumnNumber].text;
			}
		}
		if (items[i][aConditionColumnNumber] !== undefined) {
			if (items[i][aConditionColumnNumber].text !== undefined) {
				result[i].condition = items[i][aConditionColumnNumber].text;
			}
		}
		if (items[i][aValueColumnNumber] !== undefined) {
			if (items[i][aValueColumnNumber].text !== undefined) {
				result[i].value = items[i][aValueColumnNumber].text;
			}
		}
	}

	return result;
};

SpectrumQuality_Viewer.loadPeakTypes = function (aComboBox) {
	"use strict";

	var properties, peaks;

	peaks = Peak.Types;
	for (properties in peaks) {
		if (peaks.hasOwnProperty(properties)) {
			aComboBox.addItem(properties);
		}
	}
};

SpectrumQuality_Viewer.getPeakType = function () {
	"use strict";

	var dialog, showDialog, canceled, result;

	dialog = Application.loadUiFile('ricares:SpectrumQualityAddPeakType.ui');

	//Load peaks type combobox
	SpectrumQuality_Viewer.loadPeakTypes(dialog.widgets.cbPeakType);
	showDialog = true;
	canceled = false;
	while (showDialog) {
		//Check if cancel button is pulsed by user
		if (!dialog.exec()) {
			canceled = true;
			showDialog = false;
		}
		showDialog = false;
	}

	if (!canceled) {
		result = dialog.widgets.cbPeakType.currentText;
	}

	return result;
};

SpectrumQuality_Viewer.setConditionAndPeakType = function (row, col) {
	"use strict";

	var items, result;

	//We have to disconnect this signal in order to avoid problems with the totalRowsChecked counter
	this.tableWidget.cellChanged.disconnect(this, SpectrumQuality_Viewer.cellRowsChanged);
	if ((col === this.conditionParameter) || ((this.asymmetryConditionParameter !== undefined) && (col === this.asymmetryConditionParameter))) {

		//Get condition
		result = SpectrumQuality_Viewer.getCondition();

		//Set the new condition
		items = this.tableWidget.items;
		if (result !== undefined) {
			items[row][col].text = result;
		}
		items[row][col].textAlignment = 132;
		items[row][col].flags = 33;
		this.tableWidget.items = items;

	} else if (col === this.peakType) {

		//Get peakType
		result = SpectrumQuality_Viewer.getPeakType();

		//Set the new peakType
		items = this.tableWidget.items;
		if (result !== undefined) {
			items[row][col].text = result;
		}
		items[row][col].textAlignment = 132;
		items[row][col].flags = 33;
		this.tableWidget.items = items;
	}

	this.tableWidget.cellChanged.connect(this, SpectrumQuality_Viewer.cellRowsChanged);
};

SpectrumQuality_Viewer.getTotalRowsChecked = function (aTableWidget, aCheckedColumnNumber) {
	"use strict";

	var i, items, totalRowsChecked;

	totalRowsChecked = 0;
	items = aTableWidget.items;
	for (i = 0; i < items.length; i++) {
		if (aCheckedColumnNumber !== undefined) {
			if ((items[i][aCheckedColumnNumber].checkState === 2)) {
				totalRowsChecked++;
			}
		}
	}

	return totalRowsChecked;
};

SpectrumQuality_Viewer.fieldIsFilled = function (aTableWidget, aFieldColumnNumber, aCheckedColumnNumber, aNumericConstraint, aConditionColumnNumber) {
	"use strict";

	var i, items, result, value;

	result = -1;
	items = aTableWidget.items;

	if (aNumericConstraint === undefined || !aNumericConstraint) {

		for (i = 0; i < items.length; i++) {

			if (aConditionColumnNumber !== undefined && aConditionColumnNumber) {

				if (aCheckedColumnNumber !== undefined) {
					if ((items[i][aCheckedColumnNumber].checkState === 2) && (items[i][aFieldColumnNumber].text === "") && (items[i][aConditionColumnNumber].text !== undefined) && (items[i][aConditionColumnNumber].text === "")) {
						result = (i + 1);
						break;
					}
				} else if (items[i][aFieldColumnNumber].text === "") {
					result = (i + 1);
					break;
				}

			} else {

				if (aCheckedColumnNumber !== undefined) {
					if ((items[i][aCheckedColumnNumber].checkState === 2) && (items[i][aFieldColumnNumber].text === "")) {
						result = (i + 1);
						break;
					}
				} else if (items[i][aFieldColumnNumber].text === "") {
					result = (i + 1);
					break;
				}
			}
		}
	} else {

		for (i = 0; i < items.length; i++) {

			value = "";

			if (items[i][aFieldColumnNumber] !== undefined) {
				if (items[i][aFieldColumnNumber].text !== undefined) {
					if (typeof (items[i][aFieldColumnNumber].text) === "string") {
						if (items[i][aFieldColumnNumber].text !== "") {
							value = items[i][aFieldColumnNumber].text.trim();
						}
					}
				}
			}

			if (aConditionColumnNumber !== undefined && aConditionColumnNumber) {

				if (aCheckedColumnNumber !== undefined) {
					if ((items[i][aCheckedColumnNumber].checkState === 2) && (value === "") && (items[i][aConditionColumnNumber].text !== undefined) && (items[i][aConditionColumnNumber].text !== "")) {
						result = (i + 1);
						break;
					}
				} else if (value === "") {
					result = (i + 1);
					break;
				}

			} else {

				if (aCheckedColumnNumber !== undefined) {
					if ((items[i][aCheckedColumnNumber].checkState === 2) && (value === "")) {
						result = (i + 1);
						break;
					}
				} else if (value === "") {
					result = (i + 1);
					break;
				}
			}
		}
	}

	return result;
};

SpectrumQuality_Viewer.fieldIsNumber = function (aTableWidget, aFieldColumnNumber, aCheckedColumnNumber) {
	"use strict";

	var i, items, result;

	//The item must be selected and must not be a number to return false. Otherwise will return true
	result = -1;
	items = aTableWidget.items;
	for (i = 0; i < items.length; i++) {
		if (aCheckedColumnNumber !== undefined) {
			if ((items[i][aCheckedColumnNumber].checkState === 2)) {
				if (isNaN((items[i][aFieldColumnNumber].text))) {
					result = (i + 1);
					break;
				}
			}
		}
	}

	return result;
};

SpectrumQuality_Viewer.getSelectedSpectra = function (aDimension) {
	"use strict";

	var i, p, page, selItems, spectra, selPages, currentDocument, currentItem, currentSpectrum;

	selItems = [];
	spectra = [];
	currentDocument = mainWindow.activeDocument;

	if (currentDocument !== undefined) {
		if (currentDocument.uuid !== undefined) {
			if (currentDocument.uuid !== "") {
				if (currentDocument.isValid()) {
					selPages = currentDocument.selectedPages();

					if (selPages && selPages.length > 0) {
						for (p = 0; p < selPages.length; ++p) {
							for (i = 0; i < selPages[p].itemCount(); ++i) {
								currentItem = selPages[p].item(i);
								if (SpectrumQuality_Viewer.pageItemIsExpectedSpectrum(aDimension, currentItem)) {
									currentSpectrum = new NMRSpectrum(currentItem);
									spectra.push(currentSpectrum);
								}
							}
						}
					} else {
						selItems = currentDocument.selection();
						for (i = 0; i < selItems.length; i++) {
							currentItem = selItems[i];
							if (SpectrumQuality_Viewer.pageItemIsExpectedSpectrum(aDimension, currentItem)) {
								currentSpectrum = new NMRSpectrum(currentItem);
								spectra.push(currentSpectrum);
							}
						}

						if (selItems.length <= 0) {
							page = currentDocument.curPage();
							for (i = 0; i < page.itemCount(); ++i) {
								currentItem = page.item(i);
								if (SpectrumQuality_Viewer.pageItemIsExpectedSpectrum(aDimension, currentItem)) {
									currentSpectrum = new NMRSpectrum(currentItem);
									spectra.push(currentSpectrum);
								}
							}
						}
					}
				}
			}
		}
	}

	return spectra;
};

SpectrumQuality_Viewer.pageItemIsExpectedSpectrum = function (aDimension, aPageItem) {
	"use strict";

	var spectrum, result;

	result = false;
	if (aPageItem.name === "NMR Spectrum") {
		spectrum = new NMRSpectrum(aPageItem);
		if (spectrum.isValid() && spectrum.dimCount === aDimension) {
			result = true;
		}
	}

	return result;
};

SpectrumQuality_Viewer.saveResults = function () {
	"use strict";

	var file, stream, workingDirectory, results, resultContent, filePathKey;

	if (Application !== undefined) {
		if (Application.spectrumQualityResultViewer !== undefined) {
			if (Application.spectrumQualityResultViewer.resultsObject !== undefined) {
				if (Application.spectrumQualityResultViewer.resultsObject.resultsString !== undefined) {
					resultContent = Application.spectrumQualityResultViewer.resultsObject.resultsString;
				}
				if (Application.spectrumQualityResultViewer.resultsObject.filePathKey !== undefined) {
					filePathKey = Application.spectrumQualityResultViewer.resultsObject.filePathKey;
				}
			}
		}
	}

	//Write to a file if there is something to be written
	if (resultContent !== undefined) {
		try {
			if (filePathKey !== undefined) {
				workingDirectory = settings.value(filePathKey, Dir.home());
			} else {
				workingDirectory = Dir.home();
			}
			file = FileDialog.getSaveFileName("Results File (*.txt)", "Set a file to save the results", workingDirectory);
			if (file !== "") {
				results = false;
				file = new File(file);
				results = file.open(File.WriteOnly);
				stream = new TextStream(file);
				stream.codec = "UTF-8";
				results = stream.write(resultContent);
				stream.flush();
				file.close();
				if (!results) {
					MessageBox.critical(qsTr("A problem has occurred saving the results into the text file"));
				} else {
					if (filePathKey !== undefined) {
						settings.setValue(filePathKey, file.absDirPath);
					}
				}
			}
		} catch (e) {
			MessageBox.critical(qsTr("An exception has occurred saving the results into the text file:\n" + e));
		}

	} else {
		MessageBox.critical(qsTr("No results found to be saved"));
	}
};

SpectrumQuality_Viewer.copyResultsToCurrentPage = function () {
	"use strict";

	var text, textTopPosition, textLeftPosition, page;

	if (Application !== undefined) {
		if (Application.spectrumQualityResultViewer !== undefined) {
			if (Application.spectrumQualityResultViewer.resultsObject !== undefined) {
				if (Application.spectrumQualityResultViewer.resultsObject.page !== undefined) {
					if (Application.spectrumQualityResultViewer.resultsObject.page.uuid !== undefined) {
						if (Application.spectrumQualityResultViewer.resultsObject.page.uuid !== "") {
							page = Application.spectrumQualityResultViewer.resultsObject.page;
						}
					}
				}
			}
		}
	}

	if (page === undefined) {
		page = mainWindow.activeDocument.curPage();
	}

	//Write the results in the left top part of the page
	if (page !== undefined && page.uuid !== undefined && page.uuid !== "") {
		text = draw.text(SpectrumQuality_Viewer.htmlResults, true);
		textTopPosition = text.top;
		textLeftPosition = text.left;
		text.translate(page.left - textLeftPosition, page.top - textTopPosition);
		mainWindow.activeDocument.update();

	} else {
		MessageBox.critical(qsTr("Unable to copy the results to the current page"));
	}
};

SpectrumQuality_Viewer.launchViewerSettings = function () {
	"use strict";

	var i, dialog, data, showDialog, flagCancel, viewer, htmlReport,
		useSettings, fontType, fontSize, fontColor, textHighlight, separatorString;

	//Load dialog object
	dialog = Application.loadUiFile('ricares:SpectrumQualityResultsViewerSettings.ui');
	showDialog = true;
	flagCancel = false;

	//Load settings
	data = settings.value(SpectrumQuality_Viewer.richTextFlagKey, "");
	if (data !== "") {
		data = (data === "true");
		dialog.widgets.gbRichText.checked = data;
	}

	data = settings.value(SpectrumQuality_Viewer.typeFontKey, "");
	if (data !== "" && !isNaN(data)) {
		dialog.widgets.fontComboBox.currentIndex = data;
	}

	data = settings.value(SpectrumQuality_Viewer.sizeFontKey, "");
	if (data !== "" && !isNaN(data)) {
		dialog.widgets.sbFontSize.value = data;
	}

	data = settings.value(SpectrumQuality_Viewer.colorFontKey, "");
	if (!isNaN(data)) {
		if (data !== "" && !isNaN(data)) {
			dialog.widgets.colorComboBox.currentIndex = data;
		}
	} else {
		dialog.widgets.colorComboBox.addItem(settings.value(SpectrumQuality_Viewer.colorFontKey, ""));
		dialog.widgets.colorComboBox.currentIndex = dialog.widgets.colorComboBox.count - 1;
	}

	data = settings.value(SpectrumQuality_Viewer.useTestHightLightKey, "");
	if (data !== "") {
		data = (data === "true");
		dialog.widgets.cbTextHighlight.checked = data;
	}

	//Show dialog
	while (showDialog) {
		//Check if cancel button is pulsed by user
		if (!dialog.exec()) {
			flagCancel = true;
		}
		showDialog = false;
	}

	//Save settings
	if (!flagCancel) {
		settings.setValue(SpectrumQuality_Viewer.richTextFlagKey, dialog.widgets.gbRichText.checked);
		settings.setValue(SpectrumQuality_Viewer.typeFontKey, dialog.widgets.fontComboBox.currentIndex);
		settings.setValue(SpectrumQuality_Viewer.sizeFontKey, dialog.widgets.sbFontSize.value);
		settings.setValue(SpectrumQuality_Viewer.colorFontKey, dialog.widgets.colorComboBox.currentIndex);
		settings.setValue(SpectrumQuality_Viewer.useTestHightLightKey, dialog.widgets.cbTextHighlight.checked);

		if (Application.spectrumQualityResultViewer !== undefined) {
			Application.spectrumQualityResultViewer.widgets.teLog.html = "";
			viewer = new SpectrumQuality_Viewer(false);
			if (Application.spectrumQualityResultViewer.lastTextReport !== undefined) {

				useSettings = dialog.widgets.gbRichText.checked;
				fontSize = dialog.widgets.sbFontSize.value;
				fontColor = dialog.widgets.colorComboBox.currentText;
				fontType = dialog.widgets.fontComboBox.currentText;
				textHighlight = dialog.widgets.cbTextHighlight.checked;

				for (i = 0; i < Application.spectrumQualityResultViewer.lastTextReport.length; i++) {
					htmlReport = viewer.generateHTMLReport(Application.spectrumQualityResultViewer.lastTextReport[i]);
					Application.spectrumQualityResultViewer.widgets.teLog.html += htmlReport;
					if (i !== Application.spectrumQualityResultViewer.lastTextReport.length - 1) {
						if (useSettings !== undefined && useSettings) {
							separatorString = "<br><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + SpectrumQuality_Viewer.separatorSymbol + "</font><br>";
						} else {
							separatorString = "<br>" + SpectrumQuality_Viewer.separatorSymbol + "<br>";
						}
						Application.spectrumQualityResultViewer.widgets.teLog.html += separatorString;
					}
				}
			}
			SpectrumQuality_Viewer.htmlResults = Application.spectrumQualityResultViewer.widgets.teLog.html;
		}
	}
};

SpectrumQuality_Viewer.launchSettings = function () {
	"use strict";

	var i, dialog, data, showDialog, flagCancel, viewer, htmlReport, resultsDialog,
		useSettings, fontType, fontSize, fontColor, textHighlight, separatorString,
		lastTabIndex;

	//Get general settings dialog object with settings already loaded
	dialog = SpectrumQuality_Viewer.getGeneralOptionsDialogWithSettingsLoaded('ricares:SpectrumQualityGeneralSettings.ui');
	if (dialog !== undefined) {
		if (dialog.widgets !== undefined) {

			//Initialize vars
			showDialog = true;
			flagCancel = false;

			//Load results viewer settings dialog
			resultsDialog = Application.loadUiFile('ricares:SpectrumQualityResultsViewerSettings.ui');
			resultsDialog.widgets.buttonBox.visible = false;

			//Load settings into the results viewer dialog
			data = settings.value(SpectrumQuality_Viewer.richTextFlagKey, "");
			if (data !== "") {
				data = (data === "true");
				resultsDialog.widgets.gbRichText.checked = data;
			}

			data = settings.value(SpectrumQuality_Viewer.typeFontKey, "");
			if (data !== "" && !isNaN(data)) {
				resultsDialog.widgets.fontComboBox.currentIndex = data;
			}

			data = settings.value(SpectrumQuality_Viewer.sizeFontKey, "");
			if (data !== "" && !isNaN(data)) {
				resultsDialog.widgets.sbFontSize.value = data;
			}

			data = settings.value(SpectrumQuality_Viewer.colorFontKey, "");
			if (!isNaN(data)) {
				if (data !== "" && !isNaN(data)) {
					resultsDialog.widgets.colorComboBox.currentIndex = data;
				}
			} else {
				resultsDialog.widgets.colorComboBox.addItem(settings.value(SpectrumQuality_Viewer.colorFontKey, ""));
				resultsDialog.widgets.colorComboBox.currentIndex = resultsDialog.widgets.colorComboBox.count - 1;
			}

			data = settings.value(SpectrumQuality_Viewer.useTestHightLightKey, "");
			if (data !== "") {
				data = (data === "true");
				resultsDialog.widgets.cbTextHighlight.checked = data;
			}

			//Append results dialog to the corresponding tab of the main settings dialog
			dialog.widgets.tabWidget.addTab(resultsDialog, "Results Viewer");

			//Show last tab
			lastTabIndex = settings.value(SpectrumQuality_Viewer.lastTabIndexViewedKey, 0);
			if (dialog.widgets.tabWidget.count > 1) {
				dialog.widgets.tabWidget.setCurrentIndex(lastTabIndex);
			}

			//Show dialog
			while (showDialog) {
				//Check if cancel button is pulsed by user
				if (!dialog.exec()) {
					flagCancel = true;
				}
				showDialog = false;
			}

			//Save settings
			if (!flagCancel) {

				//Save settings regarding general options
				settings.setValue(SpectrumQuality_Viewer.lastTabIndexViewedKey, dialog.widgets.tabWidget.currentIndex);
				settings.setValue(SpectrumQuality_Viewer.keepCurrentDataKey, dialog.widgets.cbKeepCurrentData.checked);
				settings.setValue(SpectrumQuality_Viewer.useCurrentAnalysisKey, dialog.widgets.cbUseCurrentAnalysis.checked);

				//Save settings regarding results viewer options
				settings.setValue(SpectrumQuality_Viewer.richTextFlagKey, resultsDialog.widgets.gbRichText.checked);
				settings.setValue(SpectrumQuality_Viewer.typeFontKey, resultsDialog.widgets.fontComboBox.currentIndex);
				settings.setValue(SpectrumQuality_Viewer.sizeFontKey, resultsDialog.widgets.sbFontSize.value);
				settings.setValue(SpectrumQuality_Viewer.colorFontKey, resultsDialog.widgets.colorComboBox.currentIndex);
				settings.setValue(SpectrumQuality_Viewer.useTestHightLightKey, resultsDialog.widgets.cbTextHighlight.checked);

				if (Application.spectrumQualityResultViewer !== undefined) {
					Application.spectrumQualityResultViewer.widgets.teLog.html = "";
					viewer = new SpectrumQuality_Viewer(false);
					if (Application.spectrumQualityResultViewer.lastTextReport !== undefined) {

						useSettings = resultsDialog.widgets.gbRichText.checked;
						fontSize = resultsDialog.widgets.sbFontSize.value;
						fontColor = resultsDialog.widgets.colorComboBox.currentText;
						fontType = resultsDialog.widgets.fontComboBox.currentText;
						textHighlight = resultsDialog.widgets.cbTextHighlight.checked;

						for (i = 0; i < Application.spectrumQualityResultViewer.lastTextReport.length; i++) {
							htmlReport = viewer.generateHTMLReport(Application.spectrumQualityResultViewer.lastTextReport[i]);
							Application.spectrumQualityResultViewer.widgets.teLog.html += htmlReport;
							if (i !== Application.spectrumQualityResultViewer.lastTextReport.length - 1) {
								if (useSettings !== undefined && useSettings) {
									separatorString = "<br><font style=\"font-size: " + fontSize + "pt; font-family:'" + fontType + "'; color:'" + fontColor + "'\">" + SpectrumQuality_Viewer.separatorSymbol + "</font><br>";
								} else {
									separatorString = "<br>" + SpectrumQuality_Viewer.separatorSymbol + "<br>";
								}
								Application.spectrumQualityResultViewer.widgets.teLog.html += separatorString;
							}
						}
					}
					SpectrumQuality_Viewer.htmlResults = Application.spectrumQualityResultViewer.widgets.teLog.html;
				}
			}
		}
	}
};

SpectrumQuality_Viewer.getGeneralOptionsDialogWithSettingsLoaded = function (aPathToUIFileDialog) {
	"use strict";

	var uiFile, generalSettingsDialog, data;

	if (aPathToUIFileDialog !== undefined) {
		if (aPathToUIFileDialog !== "") {
			if (File.exists(aPathToUIFileDialog)) {
				uiFile = aPathToUIFileDialog;
				generalSettingsDialog = Application.loadUiFile(uiFile);
				data = settings.value(SpectrumQuality_Viewer.keepCurrentDataKey, "");
				if (data !== "") {
					data = (data === "true");
					generalSettingsDialog.widgets.cbKeepCurrentData.checked = data;
				}

				data = settings.value(SpectrumQuality_Viewer.useCurrentAnalysisKey, "");
				if (data !== "") {
					data = (data === "true");
					generalSettingsDialog.widgets.cbUseCurrentAnalysis.checked = data;
				}

				data = settings.value(SpectrumQuality_Viewer.lastTabIndexViewedKey, "");
				if (data !== "" && !isNaN(data)) {
					generalSettingsDialog.widgets.tabWidget.setCurrentIndex(Number(data));
				}
			}
		}
	}

	return generalSettingsDialog;
};

SpectrumQuality_Viewer.getResultsViewerOptionsDialogWithSettingsLoaded = function (aPathToUIFileDialog) {
	"use strict";

	var uiFile, resultsViewerOptionsDialog, data;

	if (aPathToUIFileDialog !== undefined) {
		if (aPathToUIFileDialog !== "") {
			if (File.exists(aPathToUIFileDialog)) {
				uiFile = aPathToUIFileDialog;
				resultsViewerOptionsDialog = Application.loadUiFile(uiFile);

				data = settings.value(SpectrumQuality_Viewer.richTextFlagKey, "");
				if (data !== "") {
					data = (data === "true");
					resultsViewerOptionsDialog.widgets.gbRichText.checked = data;
				}

				data = settings.value(SpectrumQuality_Viewer.typeFontKey, "");
				if (data !== "" && !isNaN(data)) {
					resultsViewerOptionsDialog.widgets.fontComboBox.currentIndex = data;
				}

				data = settings.value(SpectrumQuality_Viewer.sizeFontKey, "");
				if (data !== "" && !isNaN(data)) {
					resultsViewerOptionsDialog.widgets.sbFontSize.value = data;
				}

				data = settings.value(SpectrumQuality_Viewer.colorFontKey, "");
				if (!isNaN(data)) {
					if (data !== "" && !isNaN(data)) {
						resultsViewerOptionsDialog.widgets.colorComboBox.currentIndex = data;
					}
				} else {
					resultsViewerOptionsDialog.widgets.colorComboBox.addItem(settings.value(SpectrumQuality_Viewer.colorFontKey, ""));
					resultsViewerOptionsDialog.widgets.colorComboBox.currentIndex = resultsViewerOptionsDialog.widgets.colorComboBox.count - 1;
				}

				data = settings.value(SpectrumQuality_Viewer.useTestHightLightKey, "");
				if (data !== "") {
					data = (data === "true");
					resultsViewerOptionsDialog.widgets.cbTextHighlight.checked = data;
				}
			}
		}
	}

	return resultsViewerOptionsDialog;
};

/*****************************MAIN CLASS********************************
************************************************************************/
function SpectrumQuality(aSettingsMode) {
	'use strict';

	var viewer;

	//Instance the script by using the Application global variable
	try {
		viewer = new SpectrumQuality_Viewer(undefined, aSettingsMode);
	} catch (Err) {
		MessageBox.critical(Err);
	}

	return viewer;
}

if (this.MnUi && MnUi.scripts_nmr) {
	MnUi.scripts_nmr.scripts_nmr_SpectrumQuality = SpectrumQuality;
}
